Merge branch 'master' into intigrate-collect-assets

This commit is contained in:
Evan Almloff committed 2023-09-17 19:40:14 -05:00
1 parent ffb5de91d1
commit f976e08f71
379 files changed
+1962 -13517

No files matched your search

+2 -2
View File
@@ -14,10 +14,10 @@ anyhow = "1.0.66"
dioxus = { workspace = true }
dioxus-router-macro = { workspace = true }
gloo = { version = "0.8.0", optional = true }
log = { workspace = true }
tracing = { workspace = true }
thiserror = { workspace = true }
futures-util = { workspace = true }
serde_urlencoded = { version = "0.7.1", optional = true }
urlencoding = "2.1.3"
serde = { version = "1", features = ["derive"], optional = true }
url = "2.3.1"
wasm-bindgen = { workspace = true, optional = true }
+6 -8
View File
@@ -15,7 +15,7 @@
[discord-url]: https://discord.gg/XgGxMSkvUM
[Website](https://dioxuslabs.com) |
[Guides](https://dioxuslabs.com/docs/0.3/router/) |
[Guides](https://dioxuslabs.com/learn/0.4/router/) |
[API Docs](https://docs.rs/dioxus-router/latest/dioxus_router) |
[Chat](https://discord.gg/XgGxMSkvUM)
@@ -26,8 +26,6 @@ interface similar to React Router, but takes advantage of types for more
expressiveness.
```rust, no_run
#![allow(non_snake_case)]
use dioxus::prelude::*;
use dioxus_router::prelude::*;
use std::str::FromStr;
@@ -48,14 +46,14 @@ enum Route {
Index {},
}
#[component]
fn App(cx: Scope) -> Element {
render! {
Router::<Route> { }
}
}
#[inline_props]
#[component]
fn Index(cx: Scope) -> Element {
render! {
h1 { "Index" }
@@ -66,7 +64,7 @@ fn Index(cx: Scope) -> Element {
}
}
#[inline_props]
#[component]
fn Blog(cx: Scope) -> Element {
render! {
h1 { "Blog" }
@@ -74,7 +72,7 @@ fn Blog(cx: Scope) -> Element {
}
}
#[inline_props]
#[component]
fn BlogList(cx: Scope) -> Element {
render! {
h2 { "List of blog posts" }
@@ -89,7 +87,7 @@ fn BlogList(cx: Scope) -> Element {
}
}
#[inline_props]
#[component]
fn BlogPost(cx: Scope, blog_id: usize) -> Element {
render! {
h2 { "Blog Post" }
+6 -6
View File
@@ -1,4 +1,4 @@
#![allow(unused, non_snake_case)]
#![allow(unused)]
use std::time::Duration;
@@ -134,7 +134,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
#[inline_props]
#[component]
fn Blog(cx: Scope) -> Element {
render! {
div {
@@ -143,7 +143,7 @@ fn Blog(cx: Scope) -> Element {
}
}
#[inline_props]
#[component]
fn Post(cx: Scope, id: usize) -> Element {
render! {
for _ in 0..*id {
@@ -154,7 +154,7 @@ fn Post(cx: Scope, id: usize) -> Element {
}
}
#[inline_props]
#[component]
fn PostHome(cx: Scope) -> Element {
render! {
div {
@@ -163,7 +163,7 @@ fn PostHome(cx: Scope) -> Element {
}
}
#[inline_props]
#[component]
fn Home(cx: Scope) -> Element {
render! {
div {
@@ -189,7 +189,7 @@ enum Route {
Home {},
}
#[inline_props]
#[component]
fn RenderPath(cx: Scope, path: Route) -> Element {
let path = path.clone();
render! {
+7 -8
View File
@@ -1,24 +1,23 @@
#![allow(non_snake_case)]
use dioxus::prelude::*;
use dioxus_router::prelude::*;
use std::str::FromStr;
fn main() {
#[cfg(not(target_arch = "wasm32"))]
dioxus_desktop::launch(root);
dioxus_desktop::launch(Root);
#[cfg(target_arch = "wasm32")]
dioxus_web::launch(root);
}
fn root(cx: Scope) -> Element {
#[component]
fn Root(cx: Scope) -> Element {
render! {
Router::<Route> {}
}
}
#[inline_props]
#[component]
fn UserFrame(cx: Scope, user_id: usize) -> Element {
render! {
pre {
@@ -32,7 +31,7 @@ fn UserFrame(cx: Scope, user_id: usize) -> Element {
}
}
#[inline_props]
#[component]
fn Route1(cx: Scope, user_id: usize, dynamic: usize, query: String, extra: String) -> Element {
render! {
pre {
@@ -50,7 +49,7 @@ fn Route1(cx: Scope, user_id: usize, dynamic: usize, query: String, extra: Strin
}
}
#[inline_props]
#[component]
fn Route2(cx: Scope, user_id: usize) -> Element {
render! {
pre {
@@ -65,7 +64,7 @@ fn Route2(cx: Scope, user_id: usize) -> Element {
}
}
#[inline_props]
#[component]
fn Route3(cx: Scope, dynamic: String) -> Element {
let navigator = use_navigator(cx);
let current_route = use_route(cx)?;
@@ -1,5 +1,3 @@
#![allow(non_snake_case)]
use std::time::Duration;
use dioxus::prelude::*;
@@ -54,7 +52,7 @@ async fn main() {
.unwrap();
}
#[inline_props]
#[component]
fn Blog(cx: Scope) -> Element {
render! {
div {
@@ -63,7 +61,7 @@ fn Blog(cx: Scope) -> Element {
}
}
#[inline_props]
#[component]
fn Post(cx: Scope, id: usize) -> Element {
render! {
div {
@@ -72,7 +70,7 @@ fn Post(cx: Scope, id: usize) -> Element {
}
}
#[inline_props]
#[component]
fn PostHome(cx: Scope) -> Element {
render! {
div {
@@ -81,7 +79,7 @@ fn PostHome(cx: Scope) -> Element {
}
}
#[inline_props]
#[component]
fn Home(cx: Scope) -> Element {
render! {
div {
@@ -1,5 +1,5 @@
use dioxus::prelude::*;
use log::error;
use tracing::error;
use crate::utils::use_router_internal::use_router_internal;
@@ -30,13 +30,14 @@ pub struct HistoryButtonProps<'a> {
/// Index {},
/// }
///
/// #[component]
/// fn App(cx: Scope) -> Element {
/// render! {
/// Router::<Route> {}
/// }
/// }
///
/// #[inline_props]
/// #[component]
/// fn Index(cx: Scope) -> Element {
/// render! {
/// GoBackButton {
@@ -52,7 +53,7 @@ pub struct HistoryButtonProps<'a> {
/// # r#"<button disabled="true" dioxus-prevent-default="onclick">go back</button>"#
/// # );
/// ```
#[allow(non_snake_case)]
#[component]
pub fn GoBackButton<'a>(cx: Scope<'a, HistoryButtonProps<'a>>) -> Element {
let HistoryButtonProps { children } = cx.props;
@@ -101,13 +102,14 @@ pub fn GoBackButton<'a>(cx: Scope<'a, HistoryButtonProps<'a>>) -> Element {
/// Index {},
/// }
///
/// #[component]
/// fn App(cx: Scope) -> Element {
/// render! {
/// Router::<Route> {}
/// }
/// }
///
/// #[inline_props]
/// #[component]
/// fn Index(cx: Scope) -> Element {
/// render! {
/// GoForwardButton {
@@ -123,7 +125,7 @@ pub fn GoBackButton<'a>(cx: Scope<'a, HistoryButtonProps<'a>>) -> Element {
/// # r#"<button disabled="true" dioxus-prevent-default="onclick">go forward</button>"#
/// # );
/// ```
#[allow(non_snake_case)]
#[component]
pub fn GoForwardButton<'a>(cx: Scope<'a, HistoryButtonProps<'a>>) -> Element {
let HistoryButtonProps { children } = cx.props;
+5 -2
View File
@@ -1,9 +1,11 @@
#![allow(clippy::type_complexity)]
use std::any::Any;
use std::fmt::Debug;
use std::rc::Rc;
use dioxus::prelude::*;
use log::error;
use tracing::error;
use crate::navigation::NavigationTarget;
use crate::prelude::Routable;
@@ -133,13 +135,14 @@ impl Debug for LinkProps<'_> {
/// Index {},
/// }
///
/// #[component]
/// fn App(cx: Scope) -> Element {
/// render! {
/// Router::<Route> {}
/// }
/// }
///
/// #[inline_props]
/// #[component]
/// fn Index(cx: Scope) -> Element {
/// render! {
/// render! {
+4 -3
View File
@@ -29,7 +29,7 @@ use dioxus::prelude::*;
/// Index {},
/// }
///
/// #[inline_props]
/// #[component]
/// fn Index(cx: Scope) -> Element {
/// render! {
/// div {
@@ -38,7 +38,7 @@ use dioxus::prelude::*;
/// }
/// }
///
/// #[inline_props]
/// #[component]
/// fn Wrapper(cx: Scope) -> Element {
/// render! {
/// h1 { "App" }
@@ -46,7 +46,7 @@ use dioxus::prelude::*;
/// }
/// }
///
/// #[inline_props]
/// #[component]
/// fn Child(cx: Scope) -> Element {
/// render! {
/// p {
@@ -55,6 +55,7 @@ use dioxus::prelude::*;
/// }
/// }
///
/// # #[component]
/// # fn App(cx: Scope) -> Element {
/// # render! {
/// # Router::<Route> {
+2 -2
View File
@@ -20,9 +20,9 @@ where
/// ```rust
/// # use dioxus_router::prelude::*;
/// # use dioxus::prelude::*;
/// # #[inline_props]
/// # #[component]
/// # fn Index(cx: Scope) -> Element { todo!() }
/// # #[inline_props]
/// # #[component]
/// # fn OtherPage(cx: Scope) -> Element { todo!() }
/// #[derive(Clone, Routable, Debug, PartialEq)]
/// enum Route {
+17 -14
View File
@@ -48,9 +48,9 @@ pub trait HistoryProvider<R: Routable> {
/// ```rust
/// # use dioxus_router::prelude::*;
/// # use dioxus::prelude::*;
/// # #[inline_props]
/// # #[component]
/// # fn Index(cx: Scope) -> Element { todo!() }
/// # #[inline_props]
/// # #[component]
/// # fn OtherPage(cx: Scope) -> Element { todo!() }
/// #[derive(Clone, Routable, Debug, PartialEq)]
/// enum Route {
@@ -86,17 +86,20 @@ pub trait HistoryProvider<R: Routable> {
/// ```rust
/// # use dioxus_router::prelude::*;
/// # use dioxus::prelude::*;
/// # #[inline_props]
/// # #[component]
/// # fn Index(cx: Scope) -> Element { todo!() }
/// # fn Other(cx: Scope) -> Element { todo!() }
/// #[derive(Clone, Routable, Debug, PartialEq)]
/// enum Route {
/// #[route("/")]
/// Index {},
/// #[route("/other")]
/// Other {},
/// }
/// let mut history = MemoryHistory::<Route>::default();
/// assert_eq!(history.can_go_back(), false);
///
/// history.push(Route::Index {});
/// history.push(Route::Other {});
/// assert_eq!(history.can_go_back(), true);
/// ```
#[must_use]
@@ -112,9 +115,9 @@ pub trait HistoryProvider<R: Routable> {
/// ```rust
/// # use dioxus_router::prelude::*;
/// # use dioxus::prelude::*;
/// # #[inline_props]
/// # #[component]
/// # fn Index(cx: Scope) -> Element { todo!() }
/// # #[inline_props]
/// # #[component]
/// # fn OtherPage(cx: Scope) -> Element { todo!() }
/// #[derive(Clone, Routable, Debug, PartialEq)]
/// enum Route {
@@ -144,9 +147,9 @@ pub trait HistoryProvider<R: Routable> {
/// ```rust
/// # use dioxus_router::prelude::*;
/// # use dioxus::prelude::*;
/// # #[inline_props]
/// # #[component]
/// # fn Index(cx: Scope) -> Element { todo!() }
/// # #[inline_props]
/// # #[component]
/// # fn OtherPage(cx: Scope) -> Element { todo!() }
/// #[derive(Clone, Routable, Debug, PartialEq)]
/// enum Route {
@@ -177,9 +180,9 @@ pub trait HistoryProvider<R: Routable> {
/// ```rust
/// # use dioxus_router::prelude::*;
/// # use dioxus::prelude::*;
/// # #[inline_props]
/// # #[component]
/// # fn Index(cx: Scope) -> Element { todo!() }
/// # #[inline_props]
/// # #[component]
/// # fn OtherPage(cx: Scope) -> Element { todo!() }
/// #[derive(Clone, Routable, Debug, PartialEq)]
/// enum Route {
@@ -210,9 +213,9 @@ pub trait HistoryProvider<R: Routable> {
/// ```rust
/// # use dioxus_router::prelude::*;
/// # use dioxus::prelude::*;
/// # #[inline_props]
/// # #[component]
/// # fn Index(cx: Scope) -> Element { todo!() }
/// # #[inline_props]
/// # #[component]
/// # fn OtherPage(cx: Scope) -> Element { todo!() }
/// #[derive(Clone, Routable, Debug, PartialEq)]
/// enum Route {
@@ -239,9 +242,9 @@ pub trait HistoryProvider<R: Routable> {
/// ```rust
/// # use dioxus_router::prelude::*;
/// # use dioxus::prelude::*;
/// # #[inline_props]
/// # #[component]
/// # fn Index(cx: Scope) -> Element { todo!() }
/// # #[inline_props]
/// # #[component]
/// # fn OtherPage(cx: Scope) -> Element { todo!() }
/// #[derive(Clone, Routable, Debug, PartialEq)]
/// enum Route {
+5 -9
View File
@@ -139,7 +139,7 @@ impl<R: Routable> WebHistory<R> {
);
let current_route = myself.current_route();
log::trace!("initial route: {:?}", 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(&current_url));
@@ -195,14 +195,10 @@ where
<R as std::str::FromStr>::Err: std::fmt::Display,
{
fn route_from_location(&self) -> R {
R::from_str(
&self
.window
.location()
.pathname()
.unwrap_or_else(|_| String::from("/")),
)
.unwrap_or_else(|err| panic!("{}", err))
let location = self.window.location();
let path = location.pathname().unwrap_or_else(|_| "/".into())
+ &location.search().unwrap_or("".into());
R::from_str(&path).unwrap_or_else(|err| panic!("{}", err))
}
fn full_path(&self, state: &R) -> String {
+1 -1
View File
@@ -1,8 +1,8 @@
use std::sync::{Arc, Mutex};
use gloo::{events::EventListener, render::AnimationFrame, utils::window};
use log::error;
use serde::{de::DeserializeOwned, Serialize};
use tracing::error;
use url::Url;
use web_sys::{History, ScrollRestoration, Window};
+3 -2
View File
@@ -17,13 +17,14 @@ use crate::prelude::{Navigator, RouterContext};
/// Dynamic { id: usize },
/// }
///
/// #[component]
/// fn App(cx: Scope) -> Element {
/// render! {
/// Router::<Route> {}
/// }
/// }
///
/// #[inline_props]
/// #[component]
/// fn Index(cx: Scope) -> Element {
/// let navigator = use_navigator(&cx);
///
@@ -35,7 +36,7 @@ use crate::prelude::{Navigator, RouterContext};
/// }
/// }
///
/// #[inline_props]
/// #[component]
/// fn Dynamic(cx: Scope, id: usize) -> Element {
/// render! {
/// p {
+4 -3
View File
@@ -12,7 +12,7 @@ use crate::utils::use_router_internal::use_router_internal;
/// - Otherwise the current route.
///
/// # Panic
/// - When the calling component is not nested within a [`Link`] component durring a debug build.
/// - When the calling component is not nested within a [`Link`] component during a debug build.
///
/// # Example
/// ```rust
@@ -25,6 +25,7 @@ use crate::utils::use_router_internal::use_router_internal;
/// Index {},
/// }
///
/// #[component]
/// fn App(cx: Scope) -> Element {
/// render! {
/// h1 { "App" }
@@ -32,9 +33,9 @@ use crate::utils::use_router_internal::use_router_internal;
/// }
/// }
///
/// #[inline_props]
/// #[component]
/// fn Index(cx: Scope) -> Element {
/// let path = use_route(&cx).unwrap();
/// let path: Route = use_route(&cx).unwrap();
/// render! {
/// h2 { "Current Path" }
/// p { "{path}" }
+4 -4
View File
@@ -1,4 +1,4 @@
//! Exentsions to the incremental renderer to support pre-caching static routes.
//! Extensions to the incremental renderer to support pre-caching static routes.
use core::pin::Pin;
use std::future::Future;
use std::str::FromStr;
@@ -59,8 +59,8 @@ where
.await?;
}
Err(e) => {
log::info!("@ route: {}", full_path);
log::error!("Error pre-caching static route: {}", e);
tracing::info!("@ route: {}", full_path);
tracing::error!("Error pre-caching static route: {}", e);
}
}
}
@@ -87,7 +87,7 @@ where
<Rt as FromStr>::Err: std::fmt::Display,
W: tokio::io::AsyncWrite + Unpin + Send,
{
#[inline_props]
#[component]
fn RenderPath<R>(cx: Scope, path: R) -> Element
where
R: Routable,
+5
View File
@@ -82,3 +82,8 @@ pub mod prelude {
mod utils {
pub(crate) mod use_router_internal;
}
#[doc(hidden)]
pub mod exports {
pub use urlencoding;
}
+2 -2
View File
@@ -18,7 +18,7 @@ pub enum NavigationTarget<R> {
/// # use dioxus::prelude::*;
/// # use dioxus_router::prelude::*;
/// # use dioxus_router::navigation::NavigationTarget;
/// # #[inline_props]
/// # #[component]
/// # fn Index(cx: Scope) -> Element {
/// # todo!()
/// # }
@@ -38,7 +38,7 @@ pub enum NavigationTarget<R> {
/// # use dioxus::prelude::*;
/// # use dioxus_router::prelude::*;
/// # use dioxus_router::navigation::NavigationTarget;
/// # #[inline_props]
/// # #[component]
/// # fn Index(cx: Scope) -> Element {
/// # todo!()
/// # }
+126 -71
View File
@@ -3,16 +3,18 @@
#![allow(non_snake_case)]
use dioxus::prelude::*;
use std::iter::FlatMap;
use std::slice::Iter;
use std::{fmt::Display, str::FromStr};
/// An error that occurs when parsing a route
/// An error that occurs when parsing a route.
#[derive(Debug, PartialEq)]
pub struct RouteParseError<E: std::fmt::Display> {
/// The attempted routes that failed to match
pub struct RouteParseError<E: Display> {
/// The attempted routes that failed to match.
pub attempted_routes: Vec<E>,
}
impl<E: std::fmt::Display> std::fmt::Display for RouteParseError<E> {
impl<E: Display> Display for RouteParseError<E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Route did not match:\nAttempted Matches:\n")?;
for (i, route) in self.attempted_routes.iter().enumerate() {
@@ -26,63 +28,96 @@ impl<E: std::fmt::Display> std::fmt::Display for RouteParseError<E> {
///
/// This trait needs to be implemented if you want to turn a query string into a struct.
///
/// A working example can be found in the `examples` folder in the root package under `query_segments_demo`
/// A working example can be found in the `examples` folder in the root package under `query_segments_demo`.
pub trait FromQuery {
/// Create an instance of `Self` from a query string
/// Create an instance of `Self` from a query string.
fn from_query(query: &str) -> Self;
}
impl<T: for<'a> From<&'a str>> FromQuery for T {
fn from_query(query: &str) -> Self {
T::from(query)
T::from(&*urlencoding::decode(query).expect("Failed to decode url encoding"))
}
}
/// Something that can be created from a route segment
/// Something that can be created from a route segment.
pub trait FromRouteSegment: Sized {
/// The error that can occur when parsing a route segment
/// The error that can occur when parsing a route segment.
type Err;
/// Create an instance of `Self` from a route segment
/// Create an instance of `Self` from a route segment.
fn from_route_segment(route: &str) -> Result<Self, Self::Err>;
}
impl<T: FromStr> FromRouteSegment for T
where
<T as FromStr>::Err: std::fmt::Display,
<T as FromStr>::Err: Display,
{
type Err = <T as FromStr>::Err;
fn from_route_segment(route: &str) -> Result<Self, Self::Err> {
T::from_str(route)
match urlencoding::decode(route) {
Ok(segment) => T::from_str(&segment),
Err(err) => {
tracing::error!("Failed to decode url encoding: {}", err);
T::from_str(route)
}
}
}
}
/// Something that can be converted to route segments
pub trait ToRouteSegments {
/// Display the route segments
fn display_route_segements(self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
#[test]
fn full_circle() {
let route = "testing 1234 hello world";
assert_eq!(String::from_route_segment(route).unwrap(), route);
}
impl<I, T: std::fmt::Display> ToRouteSegments for I
/// Something that can be converted to route segments.
pub trait ToRouteSegments {
/// Display the route segments.
fn display_route_segments(self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
}
impl<I, T: Display> ToRouteSegments for I
where
I: IntoIterator<Item = T>,
{
fn display_route_segements(self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn display_route_segments(self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for segment in self {
write!(f, "/")?;
write!(f, "{}", segment)?;
let segment = segment.to_string();
match urlencoding::decode(&segment) {
Ok(segment) => write!(f, "{}", segment)?,
Err(err) => {
tracing::error!("Failed to decode url encoding: {}", err);
write!(f, "{}", segment)?
}
}
}
Ok(())
}
}
/// Something that can be created from route segments
#[test]
fn to_route_segments() {
struct DisplaysRoute;
impl Display for DisplaysRoute {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let segments = vec!["hello", "world"];
segments.display_route_segments(f)
}
}
assert_eq!(DisplaysRoute.to_string(), "/hello/world");
}
/// Something that can be created from route segments.
pub trait FromRouteSegments: Sized {
/// The error that can occur when parsing route segments
/// The error that can occur when parsing route segments.
type Err;
/// Create an instance of `Self` from route segments
/// Create an instance of `Self` from route segments.
fn from_route_segments(segments: &[&str]) -> Result<Self, Self::Err>;
}
@@ -97,29 +132,54 @@ impl<I: std::iter::FromIterator<String>> FromRouteSegments for I {
}
}
/// A flattened version of [`Routable::SITE_MAP`].
/// This essentially represents a `Vec<Vec<SegmentType>>`, which you can collect it into.
type SiteMapFlattened<'a> = FlatMap<
Iter<'a, SiteMapSegment>,
Vec<Vec<SegmentType>>,
fn(&SiteMapSegment) -> Vec<Vec<SegmentType>>,
>;
fn seg_strs_to_route<T>(segs_maybe: &Option<Vec<&str>>) -> Option<T>
where
T: Routable,
{
if let Some(str) = seg_strs_to_str(segs_maybe) {
T::from_str(&str).ok()
} else {
None
}
}
fn seg_strs_to_str(segs_maybe: &Option<Vec<&str>>) -> Option<String> {
segs_maybe
.as_ref()
.map(|segs| String::from('/') + &segs.join("/"))
}
/// Something that can be:
/// 1. Converted from a route
/// 2. Converted to a route
/// 3. Rendered as a component
/// 1. Converted from a route.
/// 2. Converted to a route.
/// 3. Rendered as a component.
///
/// This trait can be derived using the `#[derive(Routable)]` macro
pub trait Routable: std::fmt::Display + std::str::FromStr + Clone + 'static {
/// The error that can occur when parsing a route
/// This trait can be derived using the `#[derive(Routable)]` macro.
pub trait Routable: FromStr + Display + Clone + 'static {
/// The error that can occur when parsing a route.
const SITE_MAP: &'static [SiteMapSegment];
/// Render the route at the given level
fn render<'a>(&self, cx: &'a ScopeState, level: usize) -> Element<'a>;
/// Checks if this route is a child of the given route
/// Checks if this route is a child of the given route.
///
/// # Example
/// ```rust
/// use dioxus_router::prelude::*;
/// use dioxus::prelude::*;
///
/// #[inline_props]
/// #[component]
/// fn Home(cx: Scope) -> Element { todo!() }
/// #[inline_props]
/// #[component]
/// fn About(cx: Scope) -> Element { todo!() }
///
/// #[derive(Routable, Clone, PartialEq, Debug)]
@@ -152,23 +212,23 @@ pub trait Routable: std::fmt::Display + std::str::FromStr + Clone + 'static {
true
}
/// Get the parent route of this route
/// Get the parent route of this route.
///
/// # Example
/// ```rust
/// use dioxus_router::prelude::*;
/// use dioxus::prelude::*;
///
/// #[inline_props]
/// #[component]
/// fn Home(cx: Scope) -> Element { todo!() }
/// #[inline_props]
/// #[component]
/// fn About(cx: Scope) -> Element { todo!() }
///
/// #[derive(Routable, Clone, PartialEq, Debug)]
/// enum Route {
/// #[route("/")]
/// #[route("/home")]
/// Home {},
/// #[route("/about")]
/// #[route("/home/about")]
/// About {},
/// }
///
@@ -192,72 +252,67 @@ pub trait Routable: std::fmt::Display + std::str::FromStr + Clone + 'static {
Self::from_str(&new_route).ok()
}
/// Gets a list of all static routes
/// Returns a flattened version of [`Self::SITE_MAP`].
fn flatten_site_map<'a>() -> SiteMapFlattened<'a> {
Self::SITE_MAP.iter().flat_map(SiteMapSegment::flatten)
}
/// Gets a list of all the static routes.
/// Example static route: `#[route("/static/route")]`
fn static_routes() -> Vec<Self> {
Self::SITE_MAP
.iter()
.flat_map(|segment| segment.flatten())
Self::flatten_site_map()
.filter_map(|route| {
if route
let route_if_static = &route
.iter()
.all(|segment| matches!(segment, SegmentType::Static(_)))
{
Self::from_str(
&route
.iter()
.map(|segment| match segment {
SegmentType::Static(s) => s.to_string(),
_ => unreachable!(),
})
.collect::<Vec<_>>()
.join("/"),
)
.ok()
} else {
None
}
.map(|segment| match segment {
SegmentType::Static(s) => Some(*s),
_ => None,
})
.collect::<Option<Vec<_>>>();
seg_strs_to_route(route_if_static)
})
.collect()
}
}
trait RoutableFactory {
type Err: std::fmt::Display;
type Err: Display;
type Routable: Routable + FromStr<Err = Self::Err>;
}
impl<R: Routable + FromStr> RoutableFactory for R
where
<R as FromStr>::Err: std::fmt::Display,
<R as FromStr>::Err: Display,
{
type Err = <R as FromStr>::Err;
type Routable = R;
}
trait RouteRenderable: std::fmt::Display + 'static {
trait RouteRenderable: Display + 'static {
fn render<'a>(&self, cx: &'a ScopeState, level: usize) -> Element<'a>;
}
impl<R: Routable> RouteRenderable for R
where
<R as FromStr>::Err: std::fmt::Display,
<R as FromStr>::Err: Display,
{
fn render<'a>(&self, cx: &'a ScopeState, level: usize) -> Element<'a> {
self.render(cx, level)
}
}
/// A type erased map of the site structurens
/// A type erased map of the site structure.
#[derive(Debug, Clone, PartialEq)]
pub struct SiteMapSegment {
/// The type of the route segment
/// The type of the route segment.
pub segment_type: SegmentType,
/// The children of the route segment
/// The children of the route segment.
pub children: &'static [SiteMapSegment],
}
impl SiteMapSegment {
/// Take a map of the site structure and flatten it into a vector of routes
/// Take a map of the site structure and flatten it into a vector of routes.
pub fn flatten(&self) -> Vec<Vec<SegmentType>> {
let mut routes = Vec::new();
self.flatten_inner(&mut routes, Vec::new());
@@ -277,16 +332,16 @@ impl SiteMapSegment {
}
}
/// The type of a route segment
/// The type of a route segment.
#[derive(Debug, Clone, PartialEq)]
pub enum SegmentType {
/// A static route segment
/// A static route segment.
Static(&'static str),
/// A dynamic route segment
/// A dynamic route segment.
Dynamic(&'static str),
/// A catch all route segment
/// A catch all route segment.
CatchAll(&'static str),
/// A child router
/// A child router.
Child,
}
@@ -296,7 +351,7 @@ impl Display for SegmentType {
SegmentType::Static(s) => write!(f, "/{}", s),
SegmentType::Child => Ok(()),
SegmentType::Dynamic(s) => write!(f, "/:{}", s),
SegmentType::CatchAll(s) => write!(f, "/:...{}", s),
SegmentType::CatchAll(s) => write!(f, "/:..{}", s),
}
}
}
+1 -1
View File
@@ -13,7 +13,7 @@ use crate::prelude::*;
/// ```rust,no_run
/// # use dioxus_router::prelude::*;
/// # use dioxus::prelude::*;
/// # #[inline_props]
/// # #[component]
/// # fn Index(cx: Scope) -> Element {
/// # todo!()
/// # }
+24 -24
View File
@@ -1,4 +1,3 @@
#![allow(non_snake_case)]
use dioxus::prelude::*;
use dioxus_router::prelude::*;
use std::str::FromStr;
@@ -27,6 +26,7 @@ where
}
}
#[component]
fn App<R: Routable>(cx: Scope<AppProps<R>>) -> Element
where
<R as FromStr>::Err: std::fmt::Display,
@@ -50,12 +50,12 @@ fn href_internal() {
Test {},
}
#[inline_props]
fn Test(cx: Scope) -> Element {
#[component]
fn Test(_cx: Scope) -> Element {
todo!()
}
#[inline_props]
#[component]
fn Root(cx: Scope) -> Element {
render! {
Link {
@@ -88,12 +88,12 @@ fn href_external() {
Test {},
}
#[inline_props]
fn Test(cx: Scope) -> Element {
#[component]
fn Test(_cx: Scope) -> Element {
todo!()
}
#[inline_props]
#[component]
fn Root(cx: Scope) -> Element {
render! {
Link {
@@ -126,12 +126,12 @@ fn with_class() {
Test {},
}
#[inline_props]
fn Test(cx: Scope) -> Element {
#[component]
fn Test(_cx: Scope) -> Element {
todo!()
}
#[inline_props]
#[component]
fn Root(cx: Scope) -> Element {
render! {
Link {
@@ -163,7 +163,7 @@ fn with_active_class_active() {
Root {},
}
#[inline_props]
#[component]
fn Root(cx: Scope) -> Element {
render! {
Link {
@@ -198,12 +198,12 @@ fn with_active_class_inactive() {
Test {},
}
#[inline_props]
fn Test(cx: Scope) -> Element {
#[component]
fn Test(_cx: Scope) -> Element {
todo!()
}
#[inline_props]
#[component]
fn Root(cx: Scope) -> Element {
render! {
Link {
@@ -238,12 +238,12 @@ fn with_id() {
Test {},
}
#[inline_props]
fn Test(cx: Scope) -> Element {
#[component]
fn Test(_cx: Scope) -> Element {
todo!()
}
#[inline_props]
#[component]
fn Root(cx: Scope) -> Element {
render! {
Link {
@@ -277,12 +277,12 @@ fn with_new_tab() {
Test {},
}
#[inline_props]
fn Test(cx: Scope) -> Element {
#[component]
fn Test(_cx: Scope) -> Element {
todo!()
}
#[inline_props]
#[component]
fn Root(cx: Scope) -> Element {
render! {
Link {
@@ -314,7 +314,7 @@ fn with_new_tab_external() {
Root {},
}
#[inline_props]
#[component]
fn Root(cx: Scope) -> Element {
render! {
Link {
@@ -348,12 +348,12 @@ fn with_rel() {
Test {},
}
#[inline_props]
fn Test(cx: Scope) -> Element {
#[component]
fn Test(_cx: Scope) -> Element {
todo!()
}
#[inline_props]
#[component]
fn Root(cx: Scope) -> Element {
render! {
Link {
+9 -8
View File
@@ -1,4 +1,4 @@
#![allow(non_snake_case, unused)]
#![allow(unused)]
use dioxus::prelude::*;
use dioxus_router::prelude::*;
@@ -34,6 +34,7 @@ fn prepare(path: impl Into<String>) -> VirtualDom {
path: String,
}
#[component]
fn App(cx: Scope<AppProps>) -> Element {
render! {
h1 { "App" }
@@ -46,14 +47,14 @@ fn prepare(path: impl Into<String>) -> VirtualDom {
}
}
#[inline_props]
#[component]
fn RootIndex(cx: Scope) -> Element {
render! {
h2 { "Root Index" }
}
}
#[inline_props]
#[component]
fn Fixed(cx: Scope) -> Element {
render! {
h2 { "Fixed" }
@@ -61,21 +62,21 @@ fn prepare(path: impl Into<String>) -> VirtualDom {
}
}
#[inline_props]
#[component]
fn FixedIndex(cx: Scope) -> Element {
render! {
h3 { "Fixed - Index" }
}
}
#[inline_props]
#[component]
fn FixedFixed(cx: Scope) -> Element {
render! {
h3 { "Fixed - Fixed"}
}
}
#[inline_props]
#[component]
fn Parameter(cx: Scope, id: u8) -> Element {
render! {
h2 { "Parameter {id}" }
@@ -83,14 +84,14 @@ fn prepare(path: impl Into<String>) -> VirtualDom {
}
}
#[inline_props]
#[component]
fn ParameterIndex(cx: Scope, id: u8) -> Element {
render! {
h3 { "Parameter - Index" }
}
}
#[inline_props]
#[component]
fn ParameterFixed(cx: Scope, id: u8) -> Element {
render! {
h3 { "Parameter - Fixed" }