|
|
|
|
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; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The CSS selector to which the scroll event will be attached
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.ScrollToTop.Behavior)]
|
|
|
|
|
public string Selector { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// If set to true, it starts Visible. If sets to false, it will become visible when the TopOffset amount of scrolled pixels is reached
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.ScrollToTop.Behavior)]
|
|
|
|
|
public bool Visible { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// CSS class for the Visible state. Here, apply some transitions and animations that will happen when the component becomes visible
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.ScrollToTop.Appearance)]
|
|
|
|
|
public string VisibleCssClass { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// CSS class for the Hidden state. Here, apply some transitions and animations that will happen when the component becomes invisible
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.ScrollToTop.Appearance)]
|
|
|
|
|
public string HiddenCssClass { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The distance in pixels scrolled from the top of the selected element from which
|
|
|
|
|
/// the component becomes visible
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.ScrollToTop.Behavior)]
|
|
|
|
|
public int TopOffset { get; set; } = 300;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Smooth or Auto
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
[Category(CategoryTypes.ScrollToTop.Behavior)]
|
|
|
|
|
public ScrollBehavior ScrollBehavior { get; set; } = ScrollBehavior.Smooth;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Called when scroll event is fired
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter] public EventCallback<ScrollEventArgs> 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// event received when scroll in the selected element happens
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender">ScrollListener instance</param>
|
|
|
|
|
/// <param name="e">Information about the position of the scrolled element</param>
|
|
|
|
|
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());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Scrolls to top when clicked
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void OnClick()
|
|
|
|
|
{
|
|
|
|
|
ScrollManager.ScrollToTopAsync(_scrollListener.Selector, ScrollBehavior);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Remove the event
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
if (_scrollListener == null) { return; }
|
|
|
|
|
|
|
|
|
|
_scrollListener.OnScroll -= ScrollListener_OnScroll;
|
|
|
|
|
_scrollListener.Dispose();
|
|
|
|
|
}
|
|
|
|
|
}
|