using Connected.Annotations; using Connected.Utilities; using Microsoft.AspNetCore.Components; namespace Connected.Components; public partial class ScrollToTop : IDisposable { private IScrollListener _scrollListener; protected string Classname => new CssBuilder("mud-scroll-to-top") .AddClass("visible", Visible && string.IsNullOrWhiteSpace(VisibleCssClass)) .AddClass("hidden", !Visible && string.IsNullOrWhiteSpace(HiddenCssClass)) .AddClass(VisibleCssClass, Visible && !string.IsNullOrWhiteSpace(VisibleCssClass)) .AddClass(HiddenCssClass, !Visible && !string.IsNullOrWhiteSpace(HiddenCssClass)) .AddClass(Class) .Build(); [Inject] IScrollListenerFactory ScrollListenerFactory { get; set; } [Inject] IScrollManager ScrollManager { get; set; } [Parameter] [Category(CategoryTypes.ScrollToTop.Behavior)] public RenderFragment ChildContent { get; set; } /// /// The CSS selector to which the scroll event will be attached /// [Parameter] [Category(CategoryTypes.ScrollToTop.Behavior)] public string Selector { get; set; } /// /// If set to true, it starts Visible. If sets to false, it will become visible when the TopOffset amount of scrolled pixels is reached /// [Parameter] [Category(CategoryTypes.ScrollToTop.Behavior)] public bool Visible { get; set; } /// /// CSS class for the Visible state. Here, apply some transitions and animations that will happen when the component becomes visible /// [Parameter] [Category(CategoryTypes.ScrollToTop.Appearance)] public string VisibleCssClass { get; set; } /// /// CSS class for the Hidden state. Here, apply some transitions and animations that will happen when the component becomes invisible /// [Parameter] [Category(CategoryTypes.ScrollToTop.Appearance)] public string HiddenCssClass { get; set; } /// /// The distance in pixels scrolled from the top of the selected element from which /// the component becomes visible /// [Parameter] [Category(CategoryTypes.ScrollToTop.Behavior)] public int TopOffset { get; set; } = 300; /// /// Smooth or Auto /// [Parameter] [Category(CategoryTypes.ScrollToTop.Behavior)] public ScrollBehavior ScrollBehavior { get; set; } = ScrollBehavior.Smooth; /// /// Called when scroll event is fired /// [Parameter] public EventCallback OnScroll { get; set; } protected override void OnAfterRender(bool firstRender) { if (firstRender) { var selector = !string.IsNullOrWhiteSpace(Selector) ? Selector : null;// null is defaulted to document element in JS function _scrollListener = ScrollListenerFactory.Create(selector); //subscribe to event _scrollListener.OnScroll += ScrollListener_OnScroll; } } /// /// event received when scroll in the selected element happens /// /// ScrollListener instance /// Information about the position of the scrolled element private async void ScrollListener_OnScroll(object sender, ScrollEventArgs e) { await OnScroll.InvokeAsync(e); var topOffset = e.NodeName == "#document" ? e.FirstChildBoundingClientRect.Top * -1 : e.ScrollTop; if (topOffset >= TopOffset && Visible != true) { Visible = true; await InvokeAsync(() => StateHasChanged()); } if (topOffset < TopOffset && Visible == true) { Visible = false; await InvokeAsync(() => StateHasChanged()); } } /// /// Scrolls to top when clicked /// private void OnClick() { ScrollManager.ScrollToTopAsync(_scrollListener.Selector, ScrollBehavior); } /// /// Remove the event /// public void Dispose() { if (_scrollListener == null) { return; } _scrollListener.OnScroll -= ScrollListener_OnScroll; _scrollListener.Dispose(); } }