From a11c6303e23a32347deef3b493e90bed76518d3c Mon Sep 17 00:00:00 2001 From: koopa Date: Fri, 27 Oct 2023 21:30:30 +0200 Subject: [PATCH] feat: allow arbitrary attributes for `` component (#1953) --- router/src/components/link.rs | 106 ++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 42 deletions(-) diff --git a/router/src/components/link.rs b/router/src/components/link.rs index 88974ea12..8f947ffb6 100644 --- a/router/src/components/link.rs +++ b/router/src/components/link.rs @@ -96,6 +96,10 @@ pub fn A( /// Sets the `id` attribute on the underlying `` tag, making it easier to target. #[prop(optional, into)] id: Option>, + /// Arbitrary attributes to add to the ``. Attributes can be added with the + /// `attr:` syntax in the `view` macro. + #[prop(attrs)] + attributes: Vec<(&'static str, Attribute)>, /// The nodes or elements to be shown inside the link. children: Children, ) -> impl IntoView @@ -115,6 +119,7 @@ where class: Option, #[allow(unused)] active_class: Option>, id: Option>, + #[allow(unused)] attributes: Vec<(&'static str, Attribute)>, children: Children, ) -> View { #[cfg(not(any(feature = "hydrate", feature = "csr")))] @@ -147,74 +152,90 @@ where #[cfg(feature = "ssr")] { - // if we have `active_class`, the SSR optimization doesn't play nicely + // if we have `active_class` or arbitrary attributes, + // the SSR optimization doesn't play nicely // so we use the builder instead - if let Some(active_class) = active_class { - let mut a = leptos::html::a() - .attr("href", move || href.get().unwrap_or_default()) - .attr("target", target) - .attr("aria-current", move || { - if is_active.get() { - Some("page") - } else { - None + let needs_builder = + active_class.is_some() || !attributes.is_empty(); + if needs_builder { + let mut a = leptos::html::a() + .attr("href", move || href.get().unwrap_or_default()) + .attr("target", target) + .attr("aria-current", move || { + if is_active.get() { + Some("page") + } else { + None + } + }) + .attr( + "class", + class.map(|class| class.into_attribute_boxed()), + ); + + if let Some(active_class) = active_class { + for class_name in active_class.split_ascii_whitespace() + { + a = a.class(class_name.to_string(), move || { + is_active.get() + }) } - }) - .attr( - "class", - class.map(|class| class.into_attribute_boxed()), - ); + } - for class_name in active_class.split_ascii_whitespace() { - a = a.class(class_name.to_string(), move || is_active.get()) + a = a.attr("id", id).child(children()); + + for (attr_name, attr_value) in attributes { + a = a.attr(attr_name, attr_value); + } + + a } - - a.attr("id", id).child(children()).into_view() - } - // but keep the nice SSR optimization in most cases - else { - view! { - - {children()} - + // but keep the nice SSR optimization in most cases + else { + view! { + + {children()} + + } } .into_view() - } } // the non-SSR version doesn't need the SSR optimizations // DRY here to avoid WASM binary size bloat #[cfg(not(feature = "ssr"))] { - let a = view! { + let mut a = view! { {children()} }; + if let Some(active_class) = active_class { - let mut a = a; for class_name in active_class.split_ascii_whitespace() { a = a.class(class_name.to_string(), move || is_active.get()) } - a - } else { - a } - .into_view() + + for (attr_name, attr_value) in attributes { + a = a.attr(attr_name, attr_value); + } + + a.into_view() } } @@ -228,6 +249,7 @@ where class, active_class, id, + attributes, children, ) }