yew_scroll/lib.rs
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
use gloo::events::EventListener;
use gloo::utils::window;
use yew::prelude::*;
/// Constant defining default Tailwind CSS classes for the scroll-to-top button.
const SCROLL_TO_TOP_CLASSES: &'static str =
"fixed bottom-4 right-4 bg-blue-500 text-white p-3 rounded-full cursor-pointer hover:bg-blue-600 transition duration-300 ease-in-out";
#[derive(Properties, Clone, PartialEq)]
pub struct ScrollToTopProps {
/// Custom CSS classes for styling the scroll-to-top button.
#[prop_or(SCROLL_TO_TOP_CLASSES)]
pub css: &'static str,
/// The vertical offset value (Y position) to show the button.
#[prop_or(500.0)]
pub top_offset: f64,
/// Custom SVG content for the scroll-to-top button.
#[prop_or_else(default_svg)]
pub svg_content: Html,
}
/// scroll_to_top
/// A Yew component that provides a button to scroll to the top of the page when clicked.
///
/// # Arguments
/// * `props` - The properties of the component.
/// - `css` - Custom CSS classes for styling the scroll-to-top button. Defaults to predefined Tailwind classes.
/// - `top_offset` - The vertical offset value (Y position) to show the button. Defaults to 500.0 pixels.
/// - `svg_content` - Custom SVG content for the scroll-to-top button. Defaults to a default arrow SVG.
///
/// # Returns
/// (Html): An HTML representation of the scroll-to-top button.
///
/// # Examples
/// ```
/// // Example of using the scroll_to_top component
/// use yew::prelude::*;
/// use yew_scroll::{ScrollToTop, ScrollToTopProps};
///
/// // Custom SVG content for the scroll-to-top button (an arrow).
/// fn custom_svg() -> Html {
/// html! {
/// <svg
/// class="w-6 h-6"
/// fill="none"
/// stroke="currentColor"
/// viewBox="0 0 24 24"
/// xmlns="http://www.w3.org/2000/svg"
/// >
/// <path
/// stroke-linecap="round"
/// stroke-linejoin="round"
/// stroke-width="2"
/// d="M5 10l7-7m0 0l7 7m-7-7v18"
/// />
/// </svg>
/// }
/// }
///
/// #[function_component(MyComponent)]
/// pub fn my_component() -> Html {
/// // Set props for the scroll_to_top component
/// let scroll_to_top_props = ScrollToTopProps {
/// css: "custom-css", // Add any custom CSS classes
/// top_offset: 0.0, // Set the desired top offset value to show the button
/// svg_content: custom_svg(), // Provide custom SVG content
/// };
///
/// // Render the scroll_to_top component with the specified props
/// html! {
/// <>
/// // Other content in your component
/// <p>{"Scroll down to see the button"}</p>
///
/// // Use the scroll_to_top component
/// <ScrollToTop ..scroll_to_top_props />
///
/// // Default Usage
/// <ScrollToTop />
/// </>
/// }
/// }
/// ```
#[function_component(ScrollToTop)]
pub fn scroll_to_top(props: &ScrollToTopProps) -> Html {
// State handle to track the visibility of the scroll-to-top button.
let visible_handle = use_state(|| false);
let visible = *visible_handle;
let top_offset = props.top_offset.clone();
// Effect to add a scroll event listener and update the visibility state.
use_effect(move || {
let listener = EventListener::new(&window(), "scroll", move |_| {
let scroll_position = window().scroll_y().unwrap_or_default();
visible_handle.set(scroll_position > top_offset);
});
// Cleanup when the component is unmounted.
move || {
drop(listener);
}
});
// Callback for the button click event to scroll to the top.
let on_click = Callback::from(|_| {
let win = window();
win.scroll_to_with_x_and_y(0.0, 0.0);
});
html! {
if visible {
<div class={SCROLL_TO_TOP_CLASSES} onclick={on_click}>{ props.svg_content.clone() }</div>
}
}
}
/// Default SVG content for the scroll-to-top button (an arrow).
fn default_svg() -> Html {
html! {
<svg
class="w-6 h-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M5 10l7-7m0 0l7 7m-7-7v18"
/>
</svg>
}
}