1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
use crate::prelude::*;
use crate::router::*;
use web_sys::window;
use web_sys::{ScrollBehavior, ScrollToOptions};
/// Properties for the Link component.
#[derive(Properties, Clone, PartialEq)]
pub struct LinkProps<R: Routable + PartialEq> {
/// The target URL for the link.
pub href: R,
/// The content to be displayed within the link.
#[prop_or_default]
pub children: Html,
/// Enable scrolling behavior when clicking the link.
#[prop_or_default]
pub scroll: bool,
/// Offset for the scrolling behavior, specifying how far from the top the scroll should stop.
#[prop_or_default]
pub scroll_offset: f64,
/// Scroll behavior when clicking the link. Valid values: "auto", "instant", "smooth".
#[prop_or("auto")]
pub scroll_behavior: &'static str,
/// Callback function for handling errors, typically invoked when navigating to the link fails.
#[prop_or_default]
pub on_error: Callback<String>,
/// Indicates the current state of the link in a navigation menu. Valid values: "page", "step", "location", "date", "time", "true", "false".
#[prop_or_default]
pub aria_current: &'static str,
/// Describes the link using the ID of the element that provides a description.
#[prop_or_default]
pub aria_describedby: &'static str,
/// Indicates whether the content associated with the link is currently expanded or collapsed. Valid values: "true", "false".
#[prop_or_default]
pub aria_expanded: &'static str,
/// Indicates whether the link is currently hidden from the user. Valid values: "true", "false".
#[prop_or_default]
pub aria_hidden: &'static str,
/// Indicates whether the content associated with the link is live and dynamic. Valid values: "off", "assertive", "polite".
#[prop_or_default]
pub aria_live: &'static str,
/// Indicates whether the link is currently pressed or selected. Valid values: "true", "false", "mixed", "undefined".
#[prop_or_default]
pub aria_pressed: &'static str,
/// ID of the element that the link controls or owns.
#[prop_or_default]
pub aria_controls: &'static str,
/// ID of the element that labels the link.
#[prop_or_default]
pub aria_labelledby: &'static str,
}
/// The Link component is used for creating accessible links with additional features.
///
/// # Arguments
/// * `props` - The properties of the component.
///
/// # Returns
/// (Html): An HTML representation of the link component.
///
/// # Examples
/// ```
/// // Example of using the Link component
/// use crate::router::Route; // Your `Route` enum
/// use next_rs::{Link, LinkProps};
/// use next_rs::prelude::*;
///
/// #[function_component(MyComponent)]
/// pub fn my_component() -> Html {
///
/// html! {
/// <Link<Route>
/// scroll_offset=300.0
/// scroll_behavior="smooth"
/// href={Route::LandingPage}
/// scroll=true
/// on_error={Callback::from(|err| {
/// println!("Navigation error: {:?}", err);
/// })}
/// >{ "Go Home" }</Link<Route>>
/// }
/// }
/// ```
#[function_component(Link)]
pub fn link<R: PartialEq + Routable + 'static>(props: &LinkProps<R>) -> Html {
let navigator = use_navigator().unwrap();
let on_error_callback = props.on_error.clone();
let props = props.clone();
let onclick_callback = {
let props = props.clone();
Callback::from(move |_| {
match navigator.push(&props.href) {
() => {
on_error_callback.emit("error occurred!".to_string());
}
};
if props.scroll {
let scroll_behavior = match props.scroll_behavior {
"auto" => ScrollBehavior::Auto,
"instant" => ScrollBehavior::Instant,
"smooth" => ScrollBehavior::Smooth,
&_ => ScrollBehavior::Auto,
};
window()
.and_then(|win| {
Some(
win.scroll_to_with_scroll_to_options(
&ScrollToOptions::new()
.top(props.scroll_offset)
.behavior(scroll_behavior),
),
)
})
.expect("Failed to scroll");
}
})
};
let aria_label = "Link to ".to_string() + &props.href.to_path();
let tabindex = if props.scroll { "0" } else { "-1" };
html! {
<a
href={props.href.clone().to_path()}
onclick={onclick_callback}
role="link"
tabindex={tabindex}
aria-label={aria_label.clone()}
title={aria_label.clone()}
aria-haspopup="true"
aria-current={props.aria_current}
aria-describedby={props.aria_describedby}
aria-expanded={props.aria_expanded}
aria-hidden={props.aria_hidden}
aria-live={props.aria_live}
aria-pressed={props.aria_pressed}
aria-controls={props.aria_controls}
aria-labelledby={props.aria_labelledby}
>{ props.children.clone() }</a>
}
}