diff --git a/CodeBeam.MudExtensions.UnitTests/Components/RenderTests.cs b/CodeBeam.MudExtensions.UnitTests/Components/RenderTests.cs index 9ab7abcd..8e31e435 100644 --- a/CodeBeam.MudExtensions.UnitTests/Components/RenderTests.cs +++ b/CodeBeam.MudExtensions.UnitTests/Components/RenderTests.cs @@ -70,5 +70,12 @@ public void TextFieldExtendedPageRenderTest() var comp = Context.RenderComponent(); comp.Markup.Should().NotBeNullOrEmpty(); } + + [Test] + public void TransferListPageRenderTest() + { + var comp = Context.RenderComponent(); + comp.Markup.Should().NotBeNullOrEmpty(); + } } } diff --git a/CodeBeam.MudExtensions/Components/ListExtended/MudListExtended.razor b/CodeBeam.MudExtensions/Components/ListExtended/MudListExtended.razor index e00e2fa5..dfb48c68 100644 --- a/CodeBeam.MudExtensions/Components/ListExtended/MudListExtended.razor +++ b/CodeBeam.MudExtensions/Components/ListExtended/MudListExtended.razor @@ -8,8 +8,17 @@ @if (MultiSelection && SelectAll && SelectAllPosition == SelectAllPosition.BeforeSearchBox && ParentList == null) { - - + @if (SelectAllTemplate != null) + { +
+ @SelectAllTemplate +
+ } + else + { + + + } } @if (ItemCollection != null) diff --git a/CodeBeam.MudExtensions/Components/ListExtended/MudListExtended.razor.cs b/CodeBeam.MudExtensions/Components/ListExtended/MudListExtended.razor.cs index e3746e28..da411add 100644 --- a/CodeBeam.MudExtensions/Components/ListExtended/MudListExtended.razor.cs +++ b/CodeBeam.MudExtensions/Components/ListExtended/MudListExtended.razor.cs @@ -11,6 +11,7 @@ using MudExtensions.Enums; using MudExtensions.Services; using static MudBlazor.CategoryTypes; +using static MudBlazor.Colors; namespace MudExtensions { @@ -82,6 +83,13 @@ public partial class MudListExtended : MudComponentBase, IDisposable [Category(CategoryTypes.FormComponent.ListBehavior)] public RenderFragment> ItemDisabledTemplate { get; set; } + /// + /// Optional presentation template for select all item + /// + [Parameter] + [Category(CategoryTypes.FormComponent.ListBehavior)] + public RenderFragment SelectAllTemplate { get; set; } + [Parameter] [Category(CategoryTypes.List.Behavior)] public DefaultConverter Converter { get; set; } = new DefaultConverter(); @@ -372,7 +380,7 @@ protected void HandleCentralValueCommander(string changedValueType, bool updateS } else if (changedValueType == "MultiSelectionOff") { - SelectedValue = SelectedValues.FirstOrDefault(); + SelectedValue = SelectedValues == null ? default(T) : SelectedValues.FirstOrDefault(); var items = CollectAllMudListItems(true); SelectedValues = SelectedValue == null ? null : new HashSet(_comparer) { SelectedValue }; UpdateSelectedItem(); @@ -1313,6 +1321,20 @@ protected ICollection GetSearchedItems() return ItemCollection.Where(x => Converter.Set(x).Contains(_searchString, StringComparison.CurrentCultureIgnoreCase)).ToList(); } + public async Task ForceUpdate() + { + //if (!MultiSelection) + //{ + // SelectedValues = new HashSet(_comparer) { SelectedValue }; + //} + //else + //{ + // await SelectedValuesChanged.InvokeAsync(new HashSet(SelectedValues, _comparer)); + //} + await Task.Delay(1); + UpdateSelectedStyles(); + } + #endregion } } diff --git a/CodeBeam.MudExtensions/Components/ListExtended/MudListItemExtended.razor b/CodeBeam.MudExtensions/Components/ListExtended/MudListItemExtended.razor index 17956bba..31f79f59 100644 --- a/CodeBeam.MudExtensions/Components/ListExtended/MudListItemExtended.razor +++ b/CodeBeam.MudExtensions/Components/ListExtended/MudListItemExtended.razor @@ -4,7 +4,7 @@ @using MudBlazor @using MudExtensions.Enums -
+
@if (MudListExtended?.ItemDisabledTemplate != null && Disabled == true) { diff --git a/CodeBeam.MudExtensions/Components/ListExtended/MudListItemExtended.razor.cs b/CodeBeam.MudExtensions/Components/ListExtended/MudListItemExtended.razor.cs index 8f276dad..5c0c39ee 100644 --- a/CodeBeam.MudExtensions/Components/ListExtended/MudListItemExtended.razor.cs +++ b/CodeBeam.MudExtensions/Components/ListExtended/MudListItemExtended.razor.cs @@ -177,6 +177,13 @@ public bool Disabled [Category(CategoryTypes.List.Appearance)] public bool Inset { get; set; } + /// + /// If true, stop propagation on click. Default is true. + /// + [Parameter] + [Category(CategoryTypes.List.Appearance)] + public bool OnClickStopPropagation { get; set; } = true; + private bool? _dense; /// /// If true, compact vertical padding will be used. diff --git a/CodeBeam.MudExtensions/Components/TransferList/MudTransferList.razor b/CodeBeam.MudExtensions/Components/TransferList/MudTransferList.razor new file mode 100644 index 00000000..e030ee39 --- /dev/null +++ b/CodeBeam.MudExtensions/Components/TransferList/MudTransferList.razor @@ -0,0 +1,35 @@ +@namespace MudExtensions +@inherits MudComponentBase +@typeparam T +@using MudExtensions.Enums + + + + + @if (SelectAllType == SelectAllType.SelectAllItem) + { + + } + + +
+ @if (SelectAllType == SelectAllType.Buttons) + { + + } + + + @if (SelectAllType == SelectAllType.Buttons) + { + + } +
+ + + @if (SelectAllType == SelectAllType.SelectAllItem) + { + + } + + +
\ No newline at end of file diff --git a/CodeBeam.MudExtensions/Components/TransferList/MudTransferList.razor.cs b/CodeBeam.MudExtensions/Components/TransferList/MudTransferList.razor.cs new file mode 100644 index 00000000..dab5fb08 --- /dev/null +++ b/CodeBeam.MudExtensions/Components/TransferList/MudTransferList.razor.cs @@ -0,0 +1,302 @@ +using Microsoft.AspNetCore.Components; +using MudBlazor; +using MudBlazor.Utilities; +using MudExtensions.Enums; + +namespace MudExtensions +{ + public partial class MudTransferList : MudComponentBase + { + MudListExtended _startList; + MudListExtended _endList; + + protected string StartClassname => new CssBuilder() + .AddClass(ClassListCommon) + .AddClass(ClassStartList) + .Build(); + + protected string EndClassname => new CssBuilder() + .AddClass(ClassListCommon) + .AddClass(ClassEndList) + .Build(); + + protected string StartStylename => new StyleBuilder() + .AddStyle(StyleListCommon) + .AddStyle(StyleStartList) + .Build(); + + protected string EndStylename => new StyleBuilder() + .AddStyle(StyleListCommon) + .AddStyle(StyleEndList) + .Build(); + + /// + /// The start list's collection. + /// + [Parameter] + public ICollection StartCollection { get; set; } + + /// + /// Fires when start collection changed. + /// + [Parameter] + public EventCallback> StartCollectionChanged { get; set; } + + /// + /// The end list's collection. + /// + [Parameter] + public ICollection EndCollection { get; set; } + + /// + /// Fires when end collection changed. + /// + [Parameter] + public EventCallback> EndCollectionChanged { get; set; } + + /// + /// Fires before transfer process start. Useful to backup items or prevent transfer. + /// + [Parameter] + public EventCallback OnTransferStart { get; set; } + + /// + /// Fires when start collection changed. Takes a "StartToEnd" direction bool parameter. + /// + [Parameter] + public Func PreventTransfer { get; set; } + + /// + /// Fires when start collection changed. Takes a "StartToEnd" direction bool parameter. + /// + [Parameter] + public Func, ICollection> OrderFunc { get; set; } + + [Parameter] + public bool Vertical { get; set; } + + [Parameter] + public bool Disabled { get; set; } + + /// + /// Allows the transfer multiple items at once. + /// + [Parameter] + public bool MultiSelection { get; set; } + + [Parameter] + public MultiSelectionComponent MultiSelectionComponent { get; set; } = MultiSelectionComponent.CheckBox; + + /// + /// Select all types. If button is selected, 2 transfer all button appears. If Selectall item is selected, a list item appears. + /// + [Parameter] + public SelectAllType SelectAllType { get; set; } = SelectAllType.Buttons; + + /// + /// The color of lists and buttons. Default is primary. + /// + [Parameter] + public Color Color { get; set; } = Color.Primary; + + /// + /// The variant of buttons. + /// + [Parameter] + public Variant ButtonVariant { get; set; } = Variant.Text; + + [Parameter] + public string SelectAllText { get; set; } = "Select All"; + + [Parameter] + public int Spacing { get; set; } = 4; + + [Parameter] + public int ButtonSpacing { get; set; } = 1; + + [Parameter] + public int? MaxItems { get; set; } + + [Parameter] + public string ClassStartList { get; set; } + + [Parameter] + public string ClassEndList { get; set; } + + [Parameter] + public string ClassListCommon { get; set; } + + [Parameter] + public string StyleStartList { get; set; } + + [Parameter] + public string StyleEndList { get; set; } + + [Parameter] + public string StyleListCommon { get; set; } + + protected internal async Task Transfer(bool startToEnd = true) + { + await OnTransferStart.InvokeAsync(); + if (PreventTransfer != null && PreventTransfer.Invoke(startToEnd) == true) + { + return; + } + if (startToEnd == true) + { + if (MultiSelection == false && _startList.SelectedValue != null) + { + EndCollection.Add(_startList.SelectedValue); + StartCollection.Remove(_startList.SelectedValue); + OrderItems(); + await EndCollectionChanged.InvokeAsync(EndCollection); + await StartCollectionChanged.InvokeAsync(StartCollection); + _endList.SelectedValue = _startList.SelectedValue; + _startList.Clear(); + await _endList.ForceUpdate(); + } + else if (MultiSelection == true && _startList.SelectedValues != null) + { + ICollection transferredValues = new List(); + foreach (var item in _startList.SelectedValues) + { + // This is not a great fix, but changing multiselection true after transfering a single selection item causes a null item transfer. + if (item == null) + { + continue; + } + EndCollection.Add(item); + StartCollection.Remove(item); + transferredValues.Add(item); + } + OrderItems(); + _endList.SelectedValues = transferredValues; + if (OrderFunc != null) + { + await _endList.ForceUpdate(); + } + _startList.Clear(); + await EndCollectionChanged.InvokeAsync(EndCollection); + await StartCollectionChanged.InvokeAsync(StartCollection); + } + + } + else if (startToEnd == false) + { + if (MultiSelection == false && _endList.SelectedValue != null) + { + StartCollection.Add(_endList.SelectedValue); + EndCollection.Remove(_endList.SelectedValue); + _startList.SelectedValue = _endList.SelectedValue; + _endList.Clear(); + OrderItems(); + await StartCollectionChanged.InvokeAsync(StartCollection); + await EndCollectionChanged.InvokeAsync(EndCollection); + if (OrderFunc != null) + { + await _startList.ForceUpdate(); + } + } + else if (MultiSelection == true && _endList.SelectedValues != null) + { + ICollection transferredValues = new List(); + foreach (var item in _endList.SelectedValues) + { + if (item == null) + { + continue; + } + StartCollection.Add(item); + EndCollection.Remove(item); + transferredValues.Add(item); + } + _startList.SelectedValues = transferredValues; + OrderItems(); + await _startList.ForceUpdate(); + _endList.Clear(); + await StartCollectionChanged.InvokeAsync(StartCollection); + await EndCollectionChanged.InvokeAsync(EndCollection); + } + + } + } + + protected internal async Task TransferAll(bool startToEnd = true) + { + await OnTransferStart.InvokeAsync(); + if (PreventTransfer != null && PreventTransfer.Invoke(startToEnd) == true) + { + return; + } + if (startToEnd == true) + { + foreach (var item in StartCollection) + { + EndCollection.Add(item); + } + StartCollection.Clear(); + _startList.Clear(); + OrderItems(); + await EndCollectionChanged.InvokeAsync(EndCollection); + await StartCollectionChanged.InvokeAsync(StartCollection); + } + else if (startToEnd == false) + { + foreach (var item in EndCollection) + { + StartCollection.Add(item); + } + EndCollection.Clear(); + _endList.Clear(); + OrderItems(); + await StartCollectionChanged.InvokeAsync(StartCollection); + await EndCollectionChanged.InvokeAsync(EndCollection); + } + } + + public ICollection GetStartListSelectedValues() + { + if (_startList == null) + { + return null; + } + + if (MultiSelection == true) + { + return _startList.SelectedValues?.ToList(); + } + else + { + return new List() { _startList.SelectedValue }; + } + } + + public ICollection GetEndListSelectedValues() + { + if (_endList == null) + { + return null; + } + + if (MultiSelection == true) + { + return _endList.SelectedValues?.ToList(); + } + else + { + return new List() { _endList.SelectedValue }; + } + } + + protected void OrderItems() + { + if (OrderFunc == null) + { + return; + } + StartCollection = OrderFunc.Invoke(StartCollection); + EndCollection = OrderFunc.Invoke(EndCollection); + } + + } +} diff --git a/CodeBeam.MudExtensions/Enums/SelectAllType.cs b/CodeBeam.MudExtensions/Enums/SelectAllType.cs new file mode 100644 index 00000000..120e4406 --- /dev/null +++ b/CodeBeam.MudExtensions/Enums/SelectAllType.cs @@ -0,0 +1,14 @@ +using System.ComponentModel; + +namespace MudExtensions.Enums +{ + public enum SelectAllType + { + [Description("none")] + None, + [Description("buttons")] + Buttons, + [Description("selectallitem")] + SelectAllItem, + } +} diff --git a/ComponentViewer.Docs/Components/CodeBlock.razor b/ComponentViewer.Docs/Components/CodeBlock.razor index 1116705e..e54af6b4 100644 --- a/ComponentViewer.Docs/Components/CodeBlock.razor +++ b/ComponentViewer.Docs/Components/CodeBlock.razor @@ -1,7 +1,7 @@ @inherits MudComponentBase @namespace ComponentViewer.Docs.Components -@ChildContent +@ChildContent @code{ [Parameter] diff --git a/ComponentViewer.Docs/Components/ExampleCard.razor b/ComponentViewer.Docs/Components/ExampleCard.razor index 73ccdf76..15d1cf93 100644 --- a/ComponentViewer.Docs/Components/ExampleCard.razor +++ b/ComponentViewer.Docs/Components/ExampleCard.razor @@ -30,20 +30,22 @@ else
@ChildContent - - -
- @foreach (string line in _lines) - { - if (string.IsNullOrEmpty(line) || line == "/r") + @if (ShowCodeSection) + { + + +
+ @foreach (string line in _lines) { -
+ if (string.IsNullOrEmpty(line) || line == "/r") + { +
+ } +
@line
} -
@line
- } -
-
- +
+
+ }
@@ -65,6 +67,9 @@ else [Parameter] public bool HasExpansionPanel { get; set; } + [Parameter] + public bool ShowCodeSection { get; set; } = true; + List _lines = new(); protected override void OnParametersSet() diff --git a/ComponentViewer.Docs/Pages/Components/ApiPage.razor b/ComponentViewer.Docs/Pages/Components/ApiPage.razor index 2db5a910..496f9753 100644 --- a/ComponentViewer.Docs/Pages/Components/ApiPage.razor +++ b/ComponentViewer.Docs/Pages/Components/ApiPage.razor @@ -505,6 +505,27 @@ + + x.Name).ToList())"> + + Name + Type + Default + + + @context.Name + @context.PropertyType.Name + + @if (true) + { + MudTransferList instance = new(); + @(context.GetValue(instance)?.ToString() ?? "null") + } + + + + + x.Name).ToList())"> diff --git a/ComponentViewer.Docs/Pages/Components/ListExtendedPage.razor b/ComponentViewer.Docs/Pages/Components/ListExtendedPage.razor index 637c5447..721d8259 100644 --- a/ComponentViewer.Docs/Pages/Components/ListExtendedPage.razor +++ b/ComponentViewer.Docs/Pages/Components/ListExtendedPage.razor @@ -2,7 +2,7 @@ @using ComponentViewer.Docs.Pages.Examples - + diff --git a/ComponentViewer.Docs/Pages/Components/TransferListPage.razor b/ComponentViewer.Docs/Pages/Components/TransferListPage.razor new file mode 100644 index 00000000..7f0bdc7e --- /dev/null +++ b/ComponentViewer.Docs/Pages/Components/TransferListPage.razor @@ -0,0 +1,12 @@ +@page "/mudtransferlist" +@using ComponentViewer.Docs.Pages.Examples + + + + + + + + + + diff --git a/ComponentViewer.Docs/Pages/Examples/ChipFieldExample1.razor b/ComponentViewer.Docs/Pages/Examples/ChipFieldExample1.razor index c1553ac4..000ade2a 100644 --- a/ComponentViewer.Docs/Pages/Examples/ChipFieldExample1.razor +++ b/ComponentViewer.Docs/Pages/Examples/ChipFieldExample1.razor @@ -56,7 +56,6 @@ char _delimiter = ' '; string _value; List _values; - MudCodeInput _textFieldGroup; int _maxChips = 0; int _chipsMaxWidth = 80; Color _color = Color.Default; diff --git a/ComponentViewer.Docs/Pages/Examples/ListExtendedExampleIntro.razor b/ComponentViewer.Docs/Pages/Examples/ListExtendedExampleIntro.razor index 9858e453..f5118846 100644 --- a/ComponentViewer.Docs/Pages/Examples/ListExtendedExampleIntro.razor +++ b/ComponentViewer.Docs/Pages/Examples/ListExtendedExampleIntro.razor @@ -2,93 +2,14 @@ @using MudBlazor.Extensions - - - 1 - - - Secondary text - - - - - - 2 - - - Populate with ItemCollection parameter - - - - - - 3 - - - MultiSelection with rich customizable options - - - - - - 4 - - - Sticky Header - - - - - - 5 - - - Generic Values - - - - - - 6 - - - Virtualization (Experimental) - - - - - - 7 - - - New ScrollToMiddle scroll algorithm - - - - - - 8 - - - MaxItems for determining how many items will show - - - - - - 9 - - - Keyboard Navigation - - - - - - 10 - - - SearchBox - - + Alternative Design Pattern: Can Populate With ItemCollection parameter. + Feature: Generic Values + Feature: Secondary Text + Feature: Sticky Header + Feature: MultiSelection with Rich Customizable Options + Feature: Virtualization (Experimental) + Feature: New ScrollToMiddle scroll algorithm + Feature: Enhanced Keyboard Navigation + Feature: SearchBox + Feature: MaxItems for determining how many items will show diff --git a/ComponentViewer.Docs/Pages/Examples/SelectExtendedExampleIntro.razor b/ComponentViewer.Docs/Pages/Examples/SelectExtendedExampleIntro.razor index f0982a86..60f637ee 100644 --- a/ComponentViewer.Docs/Pages/Examples/SelectExtendedExampleIntro.razor +++ b/ComponentViewer.Docs/Pages/Examples/SelectExtendedExampleIntro.razor @@ -2,93 +2,14 @@ @using MudBlazor.Extensions - - - 1 - - - MudSelectItemExtended has the Textparameter. Users should use Text instead of RenderFragment if not certainly needed. - - - - - - 2 - - - MudSelectItemExtended can be groupable and can be nested. - - - - - - 3 - - - Support Mud Colors - - - - - - 4 - - - Can Populate With ItemCollection parameter - - - - - - 5 - - - Can show values in Chips - - - - - - 6 - - - Virtualization (Experimental) - - - - - - 7 - - - New ScrollToMiddle scroll algorithm (not completely implemented yet) - - - - - - 8 - - - Enhanced Keyboard Navigation - - - - - - 9 - - - Several Bug Fixes - - - - - - 10 - - - SearchBox - - + Alternative Design Pattern: Can Populate With ItemCollection parameter. + Design Pattern Change: MudSelectItemExtended has the Text parameter. Users should use Text instead of RenderFragment if not certainly needed. + Feature: Groups and Collapse + Feature: Support Mud Colors + Feature: Show Values With -Closeable- Chips + Feature: Virtualization (Experimental) + Feature: New ScrollToMiddle scroll algorithm (not completely implemented yet) + Feature: Enhanced Keyboard Navigation + Feature: SearchBox + Feature: Several Bug Fixes diff --git a/ComponentViewer.Docs/Pages/Examples/TextFieldExtendedExampleIntro.razor b/ComponentViewer.Docs/Pages/Examples/TextFieldExtendedExampleIntro.razor index c9ba76fd..8454d4b5 100644 --- a/ComponentViewer.Docs/Pages/Examples/TextFieldExtendedExampleIntro.razor +++ b/ComponentViewer.Docs/Pages/Examples/TextFieldExtendedExampleIntro.razor @@ -2,21 +2,6 @@ @using MudBlazor.Extensions - - - 1 - - - Dual Adornment - - - - - - 2 - - - AutoSize - - + Feature: Dual Adornment + Feature: AutoSize Textarea diff --git a/ComponentViewer.Docs/Pages/Examples/TransferListExample1.razor b/ComponentViewer.Docs/Pages/Examples/TransferListExample1.razor new file mode 100644 index 00000000..026372ca --- /dev/null +++ b/ComponentViewer.Docs/Pages/Examples/TransferListExample1.razor @@ -0,0 +1,55 @@ +@using MudBlazor.Extensions + + + + + + + + + Start Collection: @string.Join(", ", _startCollection ?? new List()) + End Collection: @string.Join(", ", _endCollection ?? new List()) + + + + + + + + + + + + +@code{ + MudTransferList _transferList; + ICollection _startCollection = new List() { "Sweden", "Hungary", "Turkey", "England", "Egypt" }; + ICollection _endCollection = new List() { "Brazil", "China", "Germany", "USA", "South Africa" }; + + bool _vertical; + bool _multiSelection; + bool _preventTurkeyTransfer; + bool _orderOnTransfer; + int? _maxItems; + SelectAllType _selectAllType = SelectAllType.Buttons; + Color _color = Color.Primary; + Variant _buttonVariant = Variant.Text; + + private bool CheckTransfer(bool startToEnd) + { + var valuesStart = _transferList.GetStartListSelectedValues(); + var valuesEnd = _transferList.GetEndListSelectedValues(); + if (_preventTurkeyTransfer == true && (valuesStart?.Contains("Turkey") == true || valuesEnd?.Contains("Turkey") == true)) + { + return true; + } + return false; + } + + private ICollection OrderMethod(ICollection e) + { + return e.Order().ToList(); + } +} diff --git a/ComponentViewer.Docs/Pages/Examples/TransferListExampleIntro.razor b/ComponentViewer.Docs/Pages/Examples/TransferListExampleIntro.razor new file mode 100644 index 00000000..b78b2ff0 --- /dev/null +++ b/ComponentViewer.Docs/Pages/Examples/TransferListExampleIntro.razor @@ -0,0 +1,7 @@ +@using MudBlazor.Extensions + + + Knowledge: SelectAll Item only show on MultiSelection. + Limitation: Null items should not use to transfer in MultiSelection. + Limitation: Constant collections like arrays can not be use in MudTransferList. + diff --git a/ComponentViewer.Docs/Pages/Index.razor b/ComponentViewer.Docs/Pages/Index.razor index 10ea9952..494f4da4 100644 --- a/ComponentViewer.Docs/Pages/Index.razor +++ b/ComponentViewer.Docs/Pages/Index.razor @@ -33,7 +33,7 @@ - + @@ -42,7 +42,7 @@
- +
@@ -70,112 +70,117 @@ - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -191,9 +196,9 @@ user-select: none; } - .slogan:hover { - letter-spacing: calc(4px + 2vw); - } + .slogan:hover { + letter-spacing: calc(4px + 2vw); + } .top-container { min-height: 100vh; @@ -203,12 +208,12 @@ .slogan3 { color: var(--mud-palette-text-primary); - font-size:24px; + font-size: 24px; font-weight: 300; } -@code{ +@code { [CascadingParameter] MainLayout MainLayout { get; set; } diff --git a/ComponentViewer.Docs/Shared/MainLayout.razor b/ComponentViewer.Docs/Shared/MainLayout.razor index 502814b7..09f5b91d 100644 --- a/ComponentViewer.Docs/Shared/MainLayout.razor +++ b/ComponentViewer.Docs/Shared/MainLayout.razor @@ -58,6 +58,7 @@ Stepper SwitchM3 TextFieldExtended + TransferList Watch Wheel