diff --git a/packages/router/src/components/link.rs b/packages/router/src/components/link.rs index 193dfa7a3..24374bda8 100644 --- a/packages/router/src/components/link.rs +++ b/packages/router/src/components/link.rs @@ -1,3 +1,5 @@ +use std::fmt::Debug; + use dioxus::prelude::*; use dioxus_router_core::{navigation::NavigationTarget, RouterMessage}; use log::error; @@ -5,7 +7,7 @@ use log::error; use crate::utils::use_router_internal::use_router_internal; /// The properties for a [`Link`]. -#[derive(Debug, Props)] +#[derive(Props)] pub struct LinkProps<'a> { /// A class to apply to the generate HTML anchor tag if the `target` route is active. pub active_class: Option<&'a str>, @@ -28,6 +30,16 @@ pub struct LinkProps<'a> { /// This does not change whether the [`Link`] is active or not. #[props(default)] pub new_tab: bool, + /// The onclick event handler. + pub onclick: Option>, + #[props(default)] + /// Whether the default behavior should be executed if an `onclick` handler is provided. + /// + /// 1. When `onclick` is [`None`] (default if not specified), `onclick_only` has no effect. + /// 2. If `onclick_only` is [`false`] (default if not specified), the provided `onclick` handler + /// will be executed after the links regular functionality. + /// 3. If `onclick_only` is [`true`], only the provided `onclick` handler will be executed. + pub onclick_only: bool, /// The rel attribute for the generated HTML anchor tag. /// /// For external `target`s, this defaults to `noopener noreferrer`. @@ -37,6 +49,23 @@ pub struct LinkProps<'a> { pub target: NavigationTarget, } +impl Debug for LinkProps<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("LinkProps") + .field("active_class", &self.active_class) + .field("children", &self.children) + .field("class", &self.class) + .field("exact", &self.exact) + .field("id", &self.id) + .field("new_tab", &self.new_tab) + .field("onclick", &self.onclick.as_ref().map(|_| "onclick is set")) + .field("onclick_only", &self.onclick_only) + .field("rel", &self.rel) + .field("target", &self.target) + .finish() + } +} + /// A link to navigate to another route. /// /// Only works as descendant of a component calling [`use_router`], otherwise it will be inactive. @@ -109,6 +138,8 @@ pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element { exact, id, new_tab, + onclick, + onclick_only, rel, target, } = cx.props; @@ -152,13 +183,22 @@ pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element { .or_else(|| is_external.then_some("noopener noreferrer")) .unwrap_or_default(); + let do_default = onclick.is_none() || !onclick_only; + let action = move |event| { + if do_default { + if is_router_nav { + let _ = sender.unbounded_send(RouterMessage::Push(target.clone())); + } + } + + if let Some(handler) = onclick { + handler.call(event); + } + }; + render! { a { - onclick: move |_| { - if is_router_nav { - let _ = sender.unbounded_send(RouterMessage::Push(target.clone())); - } - }, + onclick: action, href: "{href}", prevent_default: "{prevent_default}", class: "{class}",