2022-06-25 20:56:51 +08:00
|
|
|
|
// Licensed to the .NET Foundation under one or more agreements.
|
|
|
|
|
// The .NET Foundation licenses this file to you under the MIT license.
|
|
|
|
|
// See the LICENSE file in the project root for more information.
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using AntDesign.JsInterop;
|
|
|
|
|
using Microsoft.AspNetCore.Components;
|
|
|
|
|
|
|
|
|
|
namespace AntDesign
|
|
|
|
|
{
|
2022-11-09 17:40:16 +08:00
|
|
|
|
#if NET6_0_OR_GREATER
|
|
|
|
|
[CascadingTypeParameter(nameof(TValue))]
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-06-25 20:56:51 +08:00
|
|
|
|
public partial class Segmented<TValue> : AntDomComponentBase
|
|
|
|
|
{
|
|
|
|
|
[Parameter]
|
2022-11-09 17:40:16 +08:00
|
|
|
|
public TValue DefaultValue
|
|
|
|
|
{
|
|
|
|
|
get => _defaultValue;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_defaultValueSet = true;
|
|
|
|
|
_defaultValue = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-25 20:56:51 +08:00
|
|
|
|
|
|
|
|
|
[Parameter]
|
2022-10-11 09:21:46 +08:00
|
|
|
|
public bool Disabled
|
|
|
|
|
{
|
|
|
|
|
get => _disabled;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_disabled == value)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_disabled = value;
|
|
|
|
|
_items.ForEach(item => item.MarkStateHasChanged());
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-25 20:56:51 +08:00
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public EventCallback<TValue> OnChange { get; set; }
|
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public IEnumerable<SegmentedOption<TValue>> Options
|
|
|
|
|
{
|
|
|
|
|
get => _options;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_options != null && _options.SequenceEqual(value))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_options = value;
|
|
|
|
|
_optionValues = _options?.Select(x => x.Value).ToList() ?? new();
|
|
|
|
|
_optionsChanged = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public IEnumerable<TValue> Labels
|
|
|
|
|
{
|
|
|
|
|
get => _labels;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_labels != null && _labels.SequenceEqual(value))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_labels = value;
|
|
|
|
|
_optionValues = _labels?.ToList() ?? new();
|
|
|
|
|
_optionsChanged = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public SegmentedSize Size { get; set; }
|
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public TValue Value
|
|
|
|
|
{
|
|
|
|
|
get => _value;
|
|
|
|
|
set
|
|
|
|
|
{
|
2022-10-11 09:21:46 +08:00
|
|
|
|
if (_value is null && value is null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (_value?.Equals(value) == true)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_value = value;
|
|
|
|
|
_valueSet = true;
|
|
|
|
|
ChangeValue(_value);
|
2022-06-25 20:56:51 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public EventCallback<TValue> ValueChanged { get; set; }
|
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public RenderFragment ChildContent { get; set; }
|
|
|
|
|
|
|
|
|
|
[Parameter]
|
|
|
|
|
public bool Block { get; set; }
|
|
|
|
|
|
|
|
|
|
private IList<SegmentedItem<TValue>> _items = new List<SegmentedItem<TValue>>();
|
|
|
|
|
private Dictionary<string, HtmlElement> _itemRefs;
|
|
|
|
|
|
|
|
|
|
protected string PrefixCls => "ant-segmented";
|
|
|
|
|
|
|
|
|
|
private bool _sliding;
|
|
|
|
|
private string _slidingCls;
|
|
|
|
|
private string _slidingStyle;
|
|
|
|
|
|
|
|
|
|
private int _activeIndex;
|
|
|
|
|
|
|
|
|
|
private List<TValue> _optionValues = new List<TValue>();
|
|
|
|
|
private IEnumerable<SegmentedOption<TValue>> _options;
|
|
|
|
|
private IEnumerable<TValue> _labels;
|
|
|
|
|
private bool _optionsChanged;
|
|
|
|
|
|
|
|
|
|
private bool _firstRendered;
|
|
|
|
|
|
|
|
|
|
private TValue _value;
|
2022-10-11 09:21:46 +08:00
|
|
|
|
private bool _valueSet;
|
|
|
|
|
private bool _disabled;
|
2022-11-09 17:40:16 +08:00
|
|
|
|
private TValue _defaultValue;
|
|
|
|
|
private bool _defaultValueSet;
|
2022-06-25 20:56:51 +08:00
|
|
|
|
|
|
|
|
|
protected override void OnInitialized()
|
|
|
|
|
{
|
|
|
|
|
base.OnInitialized();
|
|
|
|
|
|
|
|
|
|
ClassMapper.Add(PrefixCls)
|
|
|
|
|
.If($"{PrefixCls}-lg", () => Size == SegmentedSize.Large)
|
|
|
|
|
.If($"{PrefixCls}-sm", () => Size == SegmentedSize.Small)
|
|
|
|
|
.If($"{PrefixCls}-disabled", () => Disabled)
|
|
|
|
|
.If($"{PrefixCls}-block", () => Block)
|
|
|
|
|
.If($"{PrefixCls}-rtl", () => RTL)
|
|
|
|
|
;
|
|
|
|
|
|
2022-11-09 17:40:16 +08:00
|
|
|
|
if (_defaultValueSet)
|
2022-06-25 20:56:51 +08:00
|
|
|
|
{
|
|
|
|
|
_value = DefaultValue;
|
|
|
|
|
ChangeValue(_value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void AddItem(SegmentedItem<TValue> item)
|
|
|
|
|
{
|
|
|
|
|
_items ??= new List<SegmentedItem<TValue>>();
|
|
|
|
|
|
|
|
|
|
_items.Add(item);
|
|
|
|
|
|
|
|
|
|
if (Labels == null && Options == null)
|
|
|
|
|
{
|
|
|
|
|
_optionValues.Add(item.Value);
|
|
|
|
|
_optionsChanged = true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-11 09:21:46 +08:00
|
|
|
|
if (!_valueSet && _optionValues?.Any() == true)
|
2022-06-25 20:56:51 +08:00
|
|
|
|
{
|
|
|
|
|
_value = _optionValues[0];
|
2022-10-11 09:21:46 +08:00
|
|
|
|
_valueSet = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_valueSet)
|
|
|
|
|
{
|
2022-06-25 20:56:51 +08:00
|
|
|
|
ChangeValue(_value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void RemoveItem(SegmentedItem<TValue> item)
|
|
|
|
|
{
|
|
|
|
|
_items?.Remove(item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
|
|
|
{
|
|
|
|
|
if (firstRender)
|
|
|
|
|
{
|
|
|
|
|
_firstRendered = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_firstRendered && _optionsChanged)
|
|
|
|
|
{
|
|
|
|
|
_optionsChanged = false;
|
2022-11-09 17:40:16 +08:00
|
|
|
|
ChangeValue(_value, true);
|
2022-06-25 20:56:51 +08:00
|
|
|
|
await GetItemElememt();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await base.OnAfterRenderAsync(firstRender);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-09 17:40:16 +08:00
|
|
|
|
private void ChangeValue(TValue value, bool noAnimation = false)
|
2022-06-25 20:56:51 +08:00
|
|
|
|
{
|
|
|
|
|
var item = _items.FirstOrDefault(x => x.Value.Equals(value));
|
|
|
|
|
if (item != null)
|
|
|
|
|
{
|
2022-11-09 17:40:16 +08:00
|
|
|
|
Select(item, noAnimation);
|
2022-06-25 20:56:51 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-09 17:40:16 +08:00
|
|
|
|
internal async void Select(SegmentedItem<TValue> item, bool noAnimation = false)
|
2022-06-25 20:56:51 +08:00
|
|
|
|
{
|
|
|
|
|
_items[_activeIndex].SetSelected(false);
|
|
|
|
|
_value = item.Value;
|
|
|
|
|
|
|
|
|
|
if (OnChange.HasDelegate)
|
|
|
|
|
{
|
|
|
|
|
await OnChange.InvokeAsync(_value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ValueChanged.HasDelegate)
|
|
|
|
|
{
|
|
|
|
|
await ValueChanged.InvokeAsync(_value);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-09 17:40:16 +08:00
|
|
|
|
if (!noAnimation)
|
|
|
|
|
{
|
|
|
|
|
await ThumbAnimation(item);
|
|
|
|
|
}
|
2022-06-25 20:56:51 +08:00
|
|
|
|
|
2023-02-13 23:10:31 +08:00
|
|
|
|
_activeIndex = _items.IndexOf(item);
|
2022-06-25 20:56:51 +08:00
|
|
|
|
_items.ForEach(x => x.SetSelected(false));
|
|
|
|
|
item.SetSelected(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task GetItemElememt()
|
|
|
|
|
{
|
|
|
|
|
var refs = _items.Select(x => x.Ref).ToArray();
|
|
|
|
|
_itemRefs = await JsInvokeAsync<Dictionary<string, HtmlElement>>(JSInteropConstants.GetElementsDomInfo, refs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task ThumbAnimation(SegmentedItem<TValue> item)
|
|
|
|
|
{
|
|
|
|
|
if (_itemRefs == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_sliding = true;
|
|
|
|
|
_slidingCls = "ant-segmented-thumb ant-segmented-thumb-motion ant-segmented-thumb-motion-appear ant-segmented-thumb-motion-appear-start";
|
|
|
|
|
_slidingStyle = $"transform: translateX({_itemRefs[_items[_activeIndex].Id].OffsetLeft}px); width: {_itemRefs[_items[_activeIndex].Id].ClientWidth}px;";
|
|
|
|
|
|
|
|
|
|
StateHasChanged();
|
|
|
|
|
await Task.Delay(100);
|
|
|
|
|
|
|
|
|
|
_slidingCls = "ant-segmented-thumb ant-segmented-thumb-motion ant-segmented-thumb-motion-appear ant-segmented-thumb-motion-appear-active ";
|
|
|
|
|
_slidingStyle = $"transform: translateX({_itemRefs[item.Id].OffsetLeft}px); width: {_itemRefs[item.Id].ClientWidth}px;";
|
|
|
|
|
|
|
|
|
|
StateHasChanged();
|
|
|
|
|
await Task.Delay(300);
|
|
|
|
|
|
|
|
|
|
_slidingCls = "";
|
|
|
|
|
_sliding = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|