document all features
This commit is contained in:
1 parent
374ff24141
commit
b4d17abfc1
21 files changed
+110
-374
No files matched your search
@@ -11,18 +11,6 @@ pub struct RouterConfigFactory<R: Routable> {
|
||||
config: Rc<RefCell<Option<Box<dyn FnOnce() -> RouterConfig<R>>>>>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<R: Routable> Default for RouterConfigFactory<R>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self::from(RouterConfig::default)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
impl<R: Routable> Default for RouterConfigFactory<R>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
@@ -40,19 +28,6 @@ impl<R: Routable, F: FnOnce() -> RouterConfig<R> + 'static> From<F> for RouterCo
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
/// The props for [`Router`].
|
||||
#[derive(Props)]
|
||||
pub struct RouterProps<R: Routable>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
#[props(default, into)]
|
||||
config: RouterConfigFactory<R>,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
/// The props for [`Router`].
|
||||
#[derive(Props)]
|
||||
pub struct RouterProps<R: Routable>
|
||||
@@ -74,7 +49,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
impl<R: Routable> Default for RouterProps<R>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
@@ -86,20 +60,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<R: Routable> Default for RouterProps<R>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
config: RouterConfigFactory::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
impl<R: Routable> PartialEq for RouterProps<R>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
@@ -110,19 +70,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<R: Routable> PartialEq for RouterProps<R>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
fn eq(&self, _: &Self) -> bool {
|
||||
// prevent the router from re-rendering when the initial url or config changes
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
/// A component that renders the current route.
|
||||
pub fn Router<R: Routable + Clone>(props: RouterProps<R>) -> Element
|
||||
where
|
||||
@@ -148,28 +95,3 @@ where
|
||||
|
||||
rsx! { Outlet::<R> {} }
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
/// A component that renders the current route.
|
||||
pub fn Router<R: Routable + Clone>(cx: ScopeState<RouterProps<R>>) -> Element
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
use_context_provider(|| {
|
||||
RouterContext::new(
|
||||
(cx.props
|
||||
.config
|
||||
.config
|
||||
.take()
|
||||
.expect("use_context_provider ran twice"))(),
|
||||
cx.schedule_update_any(),
|
||||
)
|
||||
});
|
||||
use_context_provider(|| OutletContext::<R> {
|
||||
current_level: 0,
|
||||
_marker: std::marker::PhantomData,
|
||||
});
|
||||
|
||||
rsx! { Outlet::<R> {} }
|
||||
}
|
||||
@@ -23,7 +23,6 @@ fn base_path() -> Option<&'static str> {
|
||||
base_path
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
#[allow(clippy::extra_unused_type_parameters)]
|
||||
fn update_scroll<R>(window: &Window, history: &History) {
|
||||
let scroll = ScrollPosition::of_window(window);
|
||||
@@ -32,27 +31,6 @@ fn update_scroll<R>(window: &Window, history: &History) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
fn update_scroll<R: serde::Serialize + serde::de::DeserializeOwned + Routable>(
|
||||
window: &Window,
|
||||
history: &History,
|
||||
) {
|
||||
if let Some(WebHistoryState { state, .. }) = get_current::<WebHistoryState<R>>(history) {
|
||||
let scroll = ScrollPosition::of_window(window);
|
||||
let state = WebHistoryState { state, scroll };
|
||||
if let Err(err) = replace_state_with_url(history, &state, None) {
|
||||
error!(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
struct WebHistoryState<R> {
|
||||
state: R,
|
||||
scroll: ScrollPosition,
|
||||
}
|
||||
|
||||
/// A [`HistoryProvider`] that integrates with a browser via the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API).
|
||||
///
|
||||
/// # Prefix
|
||||
@@ -75,7 +53,6 @@ pub struct WebHistory<R: Routable> {
|
||||
phantom: std::marker::PhantomData<R>,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
impl<R: Routable> Default for WebHistory<R>
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
@@ -85,19 +62,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<R: Routable> Default for WebHistory<R>
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self::new(None, true)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Routable> WebHistory<R> {
|
||||
#[cfg(not(feature = "serde"))]
|
||||
/// Create a new [`WebHistory`].
|
||||
///
|
||||
/// If `do_scroll_restoration` is [`true`], [`WebHistory`] will take control of the history
|
||||
@@ -116,47 +81,6 @@ impl<R: Routable> WebHistory<R> {
|
||||
myself
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
/// Create a new [`WebHistory`].
|
||||
///
|
||||
/// If `do_scroll_restoration` is [`true`], [`WebHistory`] will take control of the history
|
||||
/// state. It'll also set the browsers scroll restoration to `manual`.
|
||||
pub fn new(prefix: Option<String>, do_scroll_restoration: bool) -> Self
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
let w = window().expect("access to `window`");
|
||||
let h = w.history().expect("`window` has access to `history`");
|
||||
let document = w.document().expect("`window` has access to `document`");
|
||||
|
||||
let myself = Self::new_inner(
|
||||
prefix,
|
||||
do_scroll_restoration,
|
||||
EventListener::new(&document, "scroll", {
|
||||
let mut last_updated = 0.0;
|
||||
move |evt| {
|
||||
// the time stamp in milliseconds
|
||||
let time_stamp = evt.time_stamp();
|
||||
// throttle the scroll event to 100ms
|
||||
if (time_stamp - last_updated) < 100.0 {
|
||||
return;
|
||||
}
|
||||
update_scroll::<R>(&w, &h);
|
||||
last_updated = time_stamp;
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
let current_route = myself.current_route();
|
||||
tracing::trace!("initial route: {:?}", current_route);
|
||||
let current_url = current_route.to_string();
|
||||
let state = myself.create_state(current_route);
|
||||
let _ = replace_state_with_url(&myself.history, &state, Some(¤t_url));
|
||||
|
||||
myself
|
||||
}
|
||||
|
||||
fn new_inner(prefix: Option<String>, do_scroll_restoration: bool) -> Self
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
@@ -191,17 +115,10 @@ impl<R: Routable> WebHistory<R> {
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
fn create_state(&self, _state: R) -> [f64; 2] {
|
||||
let scroll = self.scroll_pos();
|
||||
[scroll.x, scroll.y]
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
fn create_state(&self, state: R) -> WebHistoryState<R> {
|
||||
let scroll = self.scroll_pos();
|
||||
WebHistoryState { state, scroll }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Routable> WebHistory<R>
|
||||
@@ -254,91 +171,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<R: serde::Serialize + serde::de::DeserializeOwned + Routable> HistoryProvider<R>
|
||||
for WebHistory<R>
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
fn current_route(&self) -> R {
|
||||
match get_current::<WebHistoryState<_>>(&self.history) {
|
||||
// Try to get the route from the history state
|
||||
Some(route) => route.state,
|
||||
// If that fails, get the route from the current URL
|
||||
None => self.route_from_location(),
|
||||
}
|
||||
}
|
||||
|
||||
fn current_prefix(&self) -> Option<String> {
|
||||
self.prefix.clone()
|
||||
}
|
||||
|
||||
fn go_back(&mut self) {
|
||||
if let Err(e) = self.history.back() {
|
||||
error!("failed to go back: ", e)
|
||||
}
|
||||
}
|
||||
|
||||
fn go_forward(&mut self) {
|
||||
if let Err(e) = self.history.forward() {
|
||||
error!("failed to go forward: ", e)
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&mut self, state: R) {
|
||||
use gloo_utils::format::JsValueSerdeExt;
|
||||
if JsValue::from_serde(&state) != JsValue::from_serde(&self.current_route()) {
|
||||
// don't push the same state twice
|
||||
return;
|
||||
}
|
||||
|
||||
let w = window().expect("access to `window`");
|
||||
let h = w.history().expect("`window` has access to `history`");
|
||||
|
||||
// update the scroll position before pushing the new state
|
||||
update_scroll::<R>(&w, &h);
|
||||
|
||||
let path = self.full_path(&state);
|
||||
|
||||
let state = self.create_state(state);
|
||||
|
||||
self.handle_nav(push_state_and_url(&self.history, &state, path));
|
||||
}
|
||||
|
||||
fn replace(&mut self, state: R) {
|
||||
let path = match &self.prefix {
|
||||
None => format!("{state}"),
|
||||
Some(prefix) => format!("{prefix}{state}"),
|
||||
};
|
||||
|
||||
let state = self.create_state(state);
|
||||
|
||||
self.handle_nav(replace_state_with_url(&self.history, &state, Some(&path)));
|
||||
}
|
||||
|
||||
fn external(&mut self, url: String) -> bool {
|
||||
self.navigate_external(url)
|
||||
}
|
||||
|
||||
fn updater(&mut self, callback: std::sync::Arc<dyn Fn() + Send + Sync>) {
|
||||
let w = self.window.clone();
|
||||
let h = self.history.clone();
|
||||
let s = self.listener_animation_frame.clone();
|
||||
let d = self.do_scroll_restoration;
|
||||
|
||||
self.listener_navigation = Some(EventListener::new(&self.window, "popstate", move |_| {
|
||||
(*callback)();
|
||||
if d {
|
||||
let mut s = s.lock().expect("unpoisoned scroll mutex");
|
||||
if let Some(current_state) = get_current::<WebHistoryState<R>>(&h) {
|
||||
*s = Some(current_state.scroll.scroll_to(w.clone()));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
impl<R: Routable> HistoryProvider<R> for WebHistory<R>
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
use gloo::console::error;
|
||||
#[cfg(feature = "serde")]
|
||||
use gloo_utils::format::JsValueSerdeExt;
|
||||
use wasm_bindgen::JsValue;
|
||||
use web_sys::History;
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
pub(crate) fn replace_state_with_url(
|
||||
history: &History,
|
||||
value: &[f64; 2],
|
||||
@@ -17,18 +14,6 @@ pub(crate) fn replace_state_with_url(
|
||||
history.replace_state_with_url(&position, "", url)
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
pub(crate) fn replace_state_with_url<V: serde::Serialize>(
|
||||
history: &History,
|
||||
value: &V,
|
||||
url: Option<&str>,
|
||||
) -> Result<(), JsValue> {
|
||||
let position = JsValue::from_serde(value).unwrap();
|
||||
|
||||
history.replace_state_with_url(&position, "", url)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
pub(crate) fn push_state_and_url(
|
||||
history: &History,
|
||||
value: &[f64; 2],
|
||||
@@ -41,33 +26,6 @@ pub(crate) fn push_state_and_url(
|
||||
history.push_state_with_url(&position, "", Some(&url))
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
pub(crate) fn push_state_and_url<V: serde::Serialize>(
|
||||
history: &History,
|
||||
value: &V,
|
||||
url: String,
|
||||
) -> Result<(), JsValue> {
|
||||
let position = JsValue::from_serde(value).unwrap();
|
||||
|
||||
history.push_state_with_url(&position, "", Some(&url))
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
pub(crate) fn get_current<V: serde::de::DeserializeOwned>(history: &History) -> Option<V> {
|
||||
let state = history.state();
|
||||
if let Err(err) = &state {
|
||||
error!(err);
|
||||
}
|
||||
state.ok().and_then(|state| {
|
||||
let deserialized = state.into_serde();
|
||||
if let Err(err) = &deserialized {
|
||||
error!(format!("{}", err));
|
||||
}
|
||||
deserialized.ok()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
pub(crate) fn get_current(history: &History) -> Option<[f64; 2]> {
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
|
||||
@@ -31,21 +31,6 @@ pub struct RouterConfig<R: Routable> {
|
||||
pub(crate) initial_route: Option<R>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<R: Routable + Clone> Default for RouterConfig<R>
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
failure_external_navigation: FailureExternalNavigation::<R>,
|
||||
history: None,
|
||||
on_update: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! default_history {
|
||||
($initial_route:ident) => {
|
||||
{
|
||||
@@ -83,24 +68,6 @@ macro_rules! default_history {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<R: Routable + Clone> RouterConfig<R>
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
pub(crate) fn get_history(self) -> Box<dyn HistoryProvider<R>> {
|
||||
#[allow(unused)]
|
||||
let initial_route = self.initial_route.clone().unwrap_or("/".parse().unwrap_or_else(|err|
|
||||
panic!("index route does not exist:\n{}\n use MemoryHistory::with_initial_path or RouterConfig::initial_route to set a custom path", err)
|
||||
));
|
||||
self.history
|
||||
.take()
|
||||
.unwrap_or_else(|| default_history!(initial_route))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
impl<R: Routable + Clone> Default for RouterConfig<R>
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
|
||||
Reference in new issue
Block a user