Skip to content

Commit

Permalink
feat(blazorui): BitCarousel component improvements #9705 (#9711)
Browse files Browse the repository at this point in the history
  • Loading branch information
msynk authored Jan 23, 2025
1 parent 9fb9aa1 commit e635a93
Show file tree
Hide file tree
Showing 11 changed files with 390 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,47 @@
class="@ClassBuilder.Value"
dir="@Dir?.ToString().ToLower()">

<div @ref="_carousel"
<div @ref="_carouselContainer"
@onpointerup="HandlePointerUp"
@onpointerleave="HandlePointerUp"
@onpointermove="HandlePointerMove"
@onpointerdown="HandlePointerDown"
@onpointerdown:preventDefault="true"
class="bit-csl-cnt"
style="@_directionStyle">
class="bit-csl-cnt @Classes?.Container"
style="@_directionStyle @Styles?.Container">

<CascadingValue Value="this" IsFixed="true">
@ChildContent
</CascadingValue>

@if (HideNextPrev is false)
{
<div class="bit-csl-lbt" @onclick="GoLeft" style="@_goLeftButtonStyle">
<i class="bit-icon bit-icon--ChevronRight" />
<div @onclick="GoLeft"
class="bit-csl-lbt @Classes?.Buttons @Classes?.GoLeftButton"
style="@_goLeftButtonStyle @Styles?.Buttons @Styles?.GoLeftButton">
<i style="@Styles?.GoLeftButtonIcon"
class="bit-icon bit-icon--@(GoLeftIcon ?? "ChevronRight") @Classes?.GoLeftButtonIcon" />
</div>

<div class="bit-csl-rbt" @onclick="GoRight" style="@_goRightButtonStyle">
<i class="bit-csl-rbi bit-icon bit-icon--ChevronRight" />
<div @onclick="GoRight"
class="bit-csl-rbt @Classes?.Buttons @Classes?.GoRightButton"
style="@_goRightButtonStyle @Styles?.Buttons @Styles?.GoRightButton">
<i style="@Styles?.GoRightButtonIcon"
class="bit-csl-rbi bit-icon bit-icon--@(GoRightIcon ?? "ChevronRight") @Classes?.GoRightButtonIcon" />
</div>
}
</div>

@if (HideDots is false)
{
<div class="bit-csl-dot" style="@_directionStyle">
<div class="bit-csl-dcn @Classes?.DotsContainer"
style="@_directionStyle @Styles?.DotsContainer">
@for (int i = 0; i < _pagesCount; i++)
{
int index = i;
<div class="@(_currentPage == index ? " current" : null)" @onclick="(() => GotoPage(index))"></div>
<div @onclick="(() => GotoPage(index))"
style="@Styles?.Dots"
class="bit-csl-dot @((_currentPage == index ? $"bit-csl-cud {Classes?.CurrectDot}" : "").Trim()) @Classes?.Dots"></div>
}
</div>
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace Bit.BlazorUI;

/// <summary>
/// Carousel (Carousel slide-show) let people show their items in seperate slides from two or more items.
/// Carousel (slide-show) let people show their items in separate slides from two or more items.
/// </summary>
public partial class BitCarousel : BitComponentBase, IAsyncDisposable
{
Expand All @@ -14,20 +14,25 @@ public partial class BitCarousel : BitComponentBase, IAsyncDisposable
private int[] _currentIndices = [];
private int _internalScrollItemsCount = 1;
private string _directionStyle = string.Empty;
private ElementReference _carousel = default!;
private string _resizeObserverId = string.Empty;
private string _goLeftButtonStyle = string.Empty;
private string _goRightButtonStyle = string.Empty;
private readonly List<BitCarouselItem> _allItems = [];
private System.Timers.Timer _autoPlayTimer = default!;
private DotNetObjectReference<BitCarousel> _dotnetObjRef = default!;
private ElementReference _carouselContainer = default!;
private DotNetObjectReference<BitCarousel> _dotnetObj = default!;



[Inject] private IJSRuntime _js { get; set; } = default!;



/// <summary>
/// Specifies the accent color kind of the component.
/// </summary>
[Parameter, ResetClassBuilder]
public BitColorKind? Accent { get; set; }

/// <summary>
/// Sets the duration of the scrolling animation in seconds (the default value is 0.5).
/// </summary>
Expand All @@ -48,6 +53,21 @@ public partial class BitCarousel : BitComponentBase, IAsyncDisposable
/// </summary>
[Parameter] public RenderFragment? ChildContent { get; set; }

/// <summary>
/// The custom CSS classes for the different parts of the carousel.
/// </summary>
[Parameter] public BitCarouselClassStyles? Classes { get; set; }

/// <summary>
/// The custom icon name for the go to left button at the right side of the carousel.
/// </summary>
[Parameter] public string? GoLeftIcon { get; set; }

/// <summary>
/// The custom icon name for the go to right button at the left side of the carousel.
/// </summary>
[Parameter] public string? GoRightIcon { get; set; }

/// <summary>
/// Hides the Dots indicator at the bottom of the BitCarousel.
/// </summary>
Expand All @@ -73,6 +93,11 @@ public partial class BitCarousel : BitComponentBase, IAsyncDisposable
/// </summary>
[Parameter] public int ScrollItemsCount { get; set; } = 1;

/// <summary>
/// The custom CSS styles for the different parts of the carousel.
/// </summary>
[Parameter] public BitCarouselClassStyles? Styles { get; set; }

/// <summary>
/// Number of items that is visible in the carousel.
/// </summary>
Expand Down Expand Up @@ -106,8 +131,8 @@ public async Task GoTo(int index)



[JSInvokable("OnRootResize")]
public async Task OnRootResize(ContentRect rect)
[JSInvokable("OnResize")]
public async Task _OnResize(ContentRect rect)
{
await ResetDimensionsAsync();
}
Expand All @@ -132,9 +157,28 @@ internal void UnregisterItem(BitCarouselItem carouselItem)

protected override string RootElementClass => "bit-csl";

protected override void RegisterCssClasses()
{
ClassBuilder.Register(() => Classes?.Root);

ClassBuilder.Register(() => Accent switch
{
BitColorKind.Primary => "bit-csl-apri",
BitColorKind.Secondary => "bit-csl-asec",
BitColorKind.Tertiary => "bit-csl-ater",
BitColorKind.Transparent => "bit-csl-atra",
_ => "bit-csl-apri"
});
}

protected override void RegisterCssStyles()
{
StyleBuilder.Register(() => Styles?.Root);
}

protected override void OnInitialized()
{
_dotnetObjRef = DotNetObjectReference.Create(this);
_dotnetObj = DotNetObjectReference.Create(this);

base.OnInitialized();
}
Expand All @@ -148,13 +192,13 @@ protected override void OnParametersSet()

protected override async Task OnAfterRenderAsync(bool firstRender)
{
_directionStyle = Dir == BitDir.Rtl ? "direction:rtl" : "";
_directionStyle = Dir == BitDir.Rtl ? "direction:rtl" : string.Empty;

await base.OnAfterRenderAsync(firstRender);

if (firstRender is false) return;

_resizeObserverId = await _js.BitObserversRegisterResize(RootElement, _dotnetObjRef, "OnRootResize");
await _js.BitObserversRegisterResize(_Id, RootElement, _dotnetObj);

if (AutoPlay)
{
Expand All @@ -179,7 +223,7 @@ private async Task ResetDimensionsAsync()
_othersIndices = Enumerable.Range(0, _internalScrollItemsCount).ToArray();

var itemsCount = _allItems.Count;
var rect = await _js.BitUtilsGetBoundingClientRect(_carousel);
var rect = await _js.BitUtilsGetBoundingClientRect(_carouselContainer);
if (rect is null) return;
var sign = Dir == BitDir.Rtl ? -1 : 1;
for (int i = 0; i < itemsCount; i++)
Expand All @@ -198,9 +242,9 @@ private async Task ResetDimensionsAsync()

private void SetNavigationButtonsVisibility()
{
_goLeftButtonStyle = (InfiniteScrolling is false && _currentIndices[_currentIndices.Length - 1] == _allItems.Count - 1) ? "display:none" : "";
_goLeftButtonStyle = (InfiniteScrolling is false && _currentIndices[_currentIndices.Length - 1] == _allItems.Count - 1) ? "display:none" : string.Empty;

_goRightButtonStyle = (InfiniteScrolling is false && _currentIndices[0] == 0) ? "display:none" : "";
_goRightButtonStyle = (InfiniteScrolling is false && _currentIndices[0] == 0) ? "display:none" : string.Empty;
}

private async Task GoLeft() => await (Dir == BitDir.Rtl ? Prev() : Next());
Expand All @@ -212,7 +256,10 @@ private async Task Prev()
_othersIndices = Enumerable.Range(0, _internalScrollItemsCount).Select(i =>
{
var idx = _currentIndices[0] - (i + 1);
if (InfiniteScrolling && idx < 0) idx += _allItems.Count;
if (InfiniteScrolling && idx < 0)
{
idx += _allItems.Count;
}
return idx;
}).Where(i => i >= 0).Reverse().ToArray();

Expand All @@ -225,7 +272,10 @@ private async Task Next()
_othersIndices = Enumerable.Range(0, _internalScrollItemsCount).Select(i =>
{
var idx = _currentIndices[_currentIndices.Length - 1] + (i + 1);
if (InfiniteScrolling && idx > itemsCount - 1) idx -= itemsCount;
if (InfiniteScrolling && idx > itemsCount - 1)
{
idx -= itemsCount;
}
return idx;
}).Where(i => i < itemsCount).ToArray();

Expand Down Expand Up @@ -255,15 +305,18 @@ private async Task Go(bool isNext = false, int scrollCount = 0)
for (int i = 0; i < others.Length; i++)
{
var o = others[i];
o.InternalTransitionStyle = "";
o.InternalTransitionStyle = string.Empty;
var x = sign * 100 * (offset + (sign * i));
x = Dir == BitDir.Rtl ? -x : x;
o.InternalTransformStyle = FormattableString.Invariant($"transform:translateX({x}%)");
}


StateHasChanged();

if (AutoPlay) _autoPlayTimer.Stop();
await Task.Delay(50);
if (AutoPlay) _autoPlayTimer.Start();

offset = isNext ? VisibleItemsCount - scrollCount : 0;

Expand Down Expand Up @@ -335,7 +388,7 @@ private async Task HandlePointerMove(MouseEventArgs e)
if (Math.Abs(delta) <= 20) return;

_isPointerDown = false;
await _js.BitUtilsSetStyle(_carousel, "cursor", "");
await _js.BitUtilsSetStyle(_carouselContainer, "cursor", string.Empty);

if (delta < 0)
{
Expand All @@ -351,14 +404,14 @@ private async Task HandlePointerDown(MouseEventArgs e)
{
_isPointerDown = true;
_pointerX = e.ClientX;
await _js.BitUtilsSetStyle(_carousel, "cursor", "grabbing");
await _js.BitUtilsSetStyle(_carouselContainer, "cursor", "grabbing");
StateHasChanged();
}

private async Task HandlePointerUp(MouseEventArgs e)
{
_isPointerDown = false;
await _js.BitUtilsSetStyle(_carousel, "cursor", "");
await _js.BitUtilsSetStyle(_carouselContainer, "cursor", string.Empty);
StateHasChanged();
}

Expand All @@ -385,12 +438,12 @@ protected virtual async ValueTask DisposeAsync(bool disposing)
_autoPlayTimer.Dispose();
}

if (_dotnetObjRef is not null)
if (_dotnetObj is not null)
{
//_dotnetObjRef.Dispose(); // it is getting disposed in the following js call:
try
{
await _js.BitObserversUnregisterResize(RootElement, _resizeObserverId, _dotnetObjRef);
await _js.BitObserversUnregisterResize(_Id, RootElement, _dotnetObj);
}
catch (JSDisconnectedException) { } // we can ignore this exception here
}
Expand Down
Loading

0 comments on commit e635a93

Please sign in to comment.