use leptos::leptos_dom::IntoView;
use leptos::*;
use crate::{use_location, use_resolved_path, State};
pub trait ToHref {
fn to_href(&self) -> Box<dyn Fn() -> String + '_>;
}
impl ToHref for &str {
fn to_href(&self) -> Box<dyn Fn() -> String> {
let s = self.to_string();
Box::new(move || s.clone())
}
}
impl ToHref for String {
fn to_href(&self) -> Box<dyn Fn() -> String> {
let s = self.clone();
Box::new(move || s.clone())
}
}
impl<F> ToHref for F
where
F: Fn() -> String + 'static,
{
fn to_href(&self) -> Box<dyn Fn() -> String + '_> {
Box::new(self)
}
}
#[component]
pub fn A<H>(
cx: Scope,
href: H,
#[prop(optional)]
exact: bool,
#[prop(optional)]
state: Option<State>,
#[prop(optional)]
replace: bool,
#[prop(optional, into)]
class: Option<MaybeSignal<String>>,
children: Box<dyn FnOnce(Scope) -> Fragment>,
) -> impl IntoView
where
H: ToHref + 'static,
{
let location = use_location(cx);
let href = use_resolved_path(cx, move || href.to_href()());
let is_active = create_memo(cx, move |_| match href.get() {
None => false,
Some(to) => {
let path = to
.split(['?', '#'])
.next()
.unwrap_or_default()
.to_lowercase();
let loc = location.pathname.get().to_lowercase();
if exact {
loc == path
} else {
loc.starts_with(&path)
}
}
});
view! { cx,
<a
href=move || href.get().unwrap_or_default()
prop:state={state.map(|s| s.to_js_value())}
prop:replace={replace}
aria-current=move || if is_active.get() { Some("page") } else { None }
class=move || class.as_ref().map(|class| class.get())
>
{children(cx)}
</a>
}
}