//! Types pertaining to navigation. use std::{ fmt::{Debug, Display}, str::FromStr, }; use url::{ParseError, Url}; use crate::routable::Routable; /// A target for the router to navigate to. #[derive(Clone, PartialEq, Eq, Debug)] pub enum NavigationTarget { /// An internal path that the router can navigate to by itself. /// /// ```rust /// # use dioxus::prelude::*; /// # use dioxus_router::prelude::*; /// # use dioxus_router::navigation::NavigationTarget; /// # #[component] /// # fn Index(cx: Scope) -> Element { /// # todo!() /// # } /// #[derive(Clone, Routable, PartialEq, Debug)] /// enum Route { /// #[route("/")] /// Index {}, /// } /// let explicit = NavigationTarget::Internal(Route::Index {}); /// let implicit: NavigationTarget:: = "/".parse().unwrap(); /// assert_eq!(explicit, implicit); /// ``` Internal(R), /// An external target that the router doesn't control. /// /// ```rust /// # use dioxus::prelude::*; /// # use dioxus_router::prelude::*; /// # use dioxus_router::navigation::NavigationTarget; /// # #[component] /// # fn Index(cx: Scope) -> Element { /// # todo!() /// # } /// #[derive(Clone, Routable, PartialEq, Debug)] /// enum Route { /// #[route("/")] /// Index {}, /// } /// let explicit = NavigationTarget::::External(String::from("https://dioxuslabs.com/")); /// let implicit: NavigationTarget:: = "https://dioxuslabs.com/".parse().unwrap(); /// assert_eq!(explicit, implicit); /// ``` External(String), } impl From<&str> for NavigationTarget { fn from(value: &str) -> Self { value .parse() .unwrap_or_else(|_| Self::External(value.to_string())) } } impl From<&String> for NavigationTarget { fn from(value: &String) -> Self { value.as_str().into() } } impl From for NavigationTarget { fn from(value: String) -> Self { value.as_str().into() } } impl From for NavigationTarget { fn from(value: R) -> Self { Self::Internal(value) } } impl Display for NavigationTarget { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { NavigationTarget::Internal(r) => write!(f, "{}", r), NavigationTarget::External(s) => write!(f, "{}", s), } } } /// An error that can occur when parsing a [`NavigationTarget`]. pub enum NavigationTargetParseError { /// A URL that is not valid. InvalidUrl(ParseError), /// An internal URL that is not valid. InvalidInternalURL(::Err), } impl Debug for NavigationTargetParseError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { NavigationTargetParseError::InvalidUrl(e) => write!(f, "Invalid URL: {}", e), NavigationTargetParseError::InvalidInternalURL(_) => { write!(f, "Invalid internal URL") } } } } impl FromStr for NavigationTarget { type Err = NavigationTargetParseError; fn from_str(s: &str) -> Result { match Url::parse(s) { Ok(_) => Ok(Self::External(s.to_string())), Err(ParseError::RelativeUrlWithoutBase) => { Ok(Self::Internal(R::from_str(s).map_err(|e| { NavigationTargetParseError::InvalidInternalURL(e) })?)) } Err(e) => Err(NavigationTargetParseError::InvalidUrl(e)), } } }