Skip to content

Commit 326f680

Browse files
authored
New Component: MudChipField (#114)
* Initialize * Detailed Features * Finalize
1 parent 5d5748f commit 326f680

File tree

12 files changed

+324
-5
lines changed

12 files changed

+324
-5
lines changed

CodeBeam.MudExtensions/Base/MudBaseInputExtended.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ protected MudBaseInputExtended() : base(new DefaultConverter<T>()) { }
106106
[Category(CategoryTypes.FormComponent.Behavior)]
107107
public bool OnlyValidateIfDirty { get; set; } = false;
108108

109+
[Parameter]
110+
[Category(CategoryTypes.FormComponent.Behavior)]
111+
public bool ForceShrink { get; set; }
112+
109113
/// <summary>
110114
/// The color of the adornment if used. It supports the theme colors.
111115
/// </summary>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
@namespace MudExtensions
2+
@inherits MudTextFieldExtended<T>
3+
@typeparam T
4+
5+
<MudTextFieldExtended
6+
@ref="_textFieldExtendedReference"
7+
T="T"
8+
Immediate="true"
9+
OnKeyDown="HandleKeyDown"
10+
OnKeyUp="HandleKeyUp"
11+
OnKeyPress="@(async() => await OnKeyPress.InvokeAsync())"
12+
OnBlur="@(async() => await OnBlur.InvokeAsync())"
13+
OnClearButtonClick="@(async() => await OnClearButtonClick.InvokeAsync())"
14+
OnDebounceIntervalElapsed="@(async() => await OnDebounceIntervalElapsed.InvokeAsync())"
15+
OnInternalInputChanged="@(async() => await OnInternalInputChanged.InvokeAsync())"
16+
ForceShrink="@(Values?.Any() ?? false)"
17+
18+
Clearable="@Clearable"
19+
AutoFocus="@AutoFocus"
20+
Class="@Class"
21+
Style="@Style"
22+
Converter="@Converter"
23+
Counter="@Counter"
24+
Culture="@Culture"
25+
DebounceInterval="@DebounceInterval"
26+
Disabled="@Disabled"
27+
DisableUnderLine="@DisableUnderLine"
28+
Error="@Error"
29+
ErrorId="@ErrorId"
30+
ErrorText="@ErrorText"
31+
For="@For"
32+
Format="@Format"
33+
FullWidth="@FullWidth"
34+
HelperText="@HelperText"
35+
HelperTextOnFocus="@HelperTextOnFocus"
36+
Label="@Label"
37+
Margin="@Margin"
38+
MaxLength="@MaxLength"
39+
OnlyValidateIfDirty="@OnlyValidateIfDirty"
40+
ReadOnly="@ReadOnly"
41+
Placeholder="@Placeholder"
42+
Required="@Required"
43+
RequiredError="@RequiredError"
44+
Validation="@Validation"
45+
Variant="@Variant"
46+
@bind-Value="@_internalValue"
47+
TextChanged="@(async() => await TextChanged.InvokeAsync())">
48+
49+
<DataVisualiser>
50+
<MudChipSet Class="@ChipClassname" Style="@ChipStylename" AllClosable="@Closeable" OnClose="Closed">
51+
@for (int i = 0; i < (MaxChips == 0 ? Values?.Count ?? 0 : (MaxChips < (Values?.Count ?? 0) ? MaxChips : Values?.Count ?? 0)); i++)
52+
{
53+
int a = i;
54+
<MudChip Class="@ClassChip" Style="@StyleChip" DisableRipple="true" Text="@Values[a]" Color="@ChipColor" Variant="@ChipVariant" Size="@ChipSize" Disabled="@Disabled" />
55+
}
56+
</MudChipSet>
57+
@if (Values != null && MaxChips != 0 && MaxChips < Values.Count)
58+
{
59+
<MudChip DisableRipple="true" Text="@($"+{Values.Count - MaxChips}")" Color="@ChipColor" Variant="@ChipVariant" Size="@ChipSize" Disabled="@Disabled" />
60+
}
61+
</DataVisualiser>
62+
63+
<AdornmentEnd>
64+
@AdornmentEnd
65+
</AdornmentEnd>
66+
67+
</MudTextFieldExtended>
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
using Microsoft.AspNetCore.Components;
2+
using Microsoft.AspNetCore.Components.Web;
3+
using MudBlazor;
4+
using MudBlazor.Utilities;
5+
6+
namespace MudExtensions
7+
{
8+
public partial class MudChipField<T> : MudTextFieldExtended<T>
9+
{
10+
protected string ChipClassname =>
11+
new CssBuilder("d-flex")
12+
.AddClass("flex-wrap", WrapChips)
13+
.AddClass("mt-5", Variant == Variant.Filled)
14+
.Build();
15+
16+
protected string ChipStylename =>
17+
new StyleBuilder()
18+
.AddStyle("max-width", $"{ChipsMaxWidth}%")
19+
.Build();
20+
21+
MudTextFieldExtended<T> _textFieldExtendedReference;
22+
T _internalValue;
23+
24+
/// <summary>
25+
/// /The list of values.
26+
/// </summary>
27+
[Parameter]
28+
public List<string> Values { get; set; }
29+
30+
/// <summary>
31+
/// Fires when values changed
32+
/// </summary>
33+
[Parameter]
34+
public EventCallback<List<string>> ValuesChanged { get; set; }
35+
36+
[Parameter]
37+
public Size ChipSize { get; set; }
38+
39+
/// <summary>
40+
/// The char that created a new chip with current value.
41+
/// </summary>
42+
[Parameter]
43+
public char Delimiter { get; set; }
44+
45+
[Parameter]
46+
public string ClassChip { get; set; }
47+
48+
[Parameter]
49+
public string StyleChip { get; set; }
50+
51+
[Parameter]
52+
public Color ChipColor { get; set; }
53+
54+
[Parameter]
55+
public Variant ChipVariant { get; set; }
56+
57+
[Parameter]
58+
public bool WrapChips { get; set; }
59+
60+
/// <summary>
61+
/// Determines that chips have close button. Default is true.
62+
/// </summary>
63+
[Parameter]
64+
public bool Closeable { get; set; } = true;
65+
66+
[Parameter]
67+
public int MaxChips { get; set; }
68+
69+
[Parameter]
70+
public int ChipsMaxWidth { get; set; } = 80;
71+
72+
protected async Task HandleKeyDown(KeyboardEventArgs args)
73+
{
74+
75+
if (args.Key == Delimiter.ToString() && _internalValue != null)
76+
{
77+
await SetChips();
78+
StateHasChanged();
79+
}
80+
81+
if (args.Key == "Backspace" && string.IsNullOrEmpty(Converter.Set(_internalValue)) && Values.Any())
82+
{
83+
Values.RemoveAt(Values.Count - 1);
84+
await ValuesChanged.InvokeAsync(Values);
85+
}
86+
await Task.Delay(10);
87+
await SetValueAsync(_internalValue);
88+
await OnKeyDown.InvokeAsync(args);
89+
}
90+
91+
protected async Task HandleKeyUp(KeyboardEventArgs args)
92+
{
93+
await OnKeyUp.InvokeAsync(args);
94+
}
95+
96+
protected async Task SetChips()
97+
{
98+
if (Values == null)
99+
{
100+
Values = new();
101+
}
102+
Values.Add(Converter.Set(_internalValue));
103+
await ValuesChanged.InvokeAsync(Values);
104+
if (RuntimeLocation.IsServerSide)
105+
{
106+
await _textFieldExtendedReference.BlurAsync();
107+
}
108+
else
109+
{
110+
await Task.Delay((int)DebounceInterval + 10);
111+
}
112+
await _textFieldExtendedReference.Clear();
113+
if (RuntimeLocation.IsServerSide)
114+
{
115+
await _textFieldExtendedReference.FocusAsync();
116+
}
117+
}
118+
119+
public async Task Closed(MudChip chip)
120+
{
121+
if (Disabled || ReadOnly)
122+
{
123+
return;
124+
}
125+
Values.Remove(chip.Text);
126+
await ValuesChanged.InvokeAsync(Values);
127+
await _textFieldExtendedReference.FocusAsync();
128+
}
129+
130+
}
131+
}

CodeBeam.MudExtensions/Components/InputExtended/MudInputExtended.razor

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
@using MudBlazor.Internal
55

66
<div class="@Classname" style="@Style">
7-
7+
88
@if (AdornmentStart != null)
99
{
1010
<div class="@AdornmentStartClassname">
1111
@AdornmentStart
1212
</div>
1313
}
14-
14+
1515
@if (Lines > 1)
1616
{
1717
<textarea class="@InputClassname"
@@ -46,7 +46,6 @@
4646
}
4747
else
4848
{
49-
5049
@if (DataVisualiser != null)
5150
{
5251
@DataVisualiser

CodeBeam.MudExtensions/Components/InputExtended/MudInputExtended.razor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public partial class MudInputExtended<T> : MudBaseInputExtended<T>
1414
[Inject] IJSRuntime JSRuntime { get; set; }
1515

1616
protected string Classname => MudInputCssHelperExtended.GetClassname(this,
17-
() => HasNativeHtmlPlaceholder() || !string.IsNullOrEmpty(Text) || AdornmentStart != null || !string.IsNullOrWhiteSpace(Placeholder) || !string.IsNullOrEmpty(Converter.Set(Value)));
17+
() => HasNativeHtmlPlaceholder() || ForceShrink == true || !string.IsNullOrEmpty(Text) || AdornmentStart != null || !string.IsNullOrWhiteSpace(Placeholder) || !string.IsNullOrEmpty(Converter.Set(Value)));
1818

1919
protected string InputClassname => MudInputCssHelperExtended.GetInputClassname(this);
2020

CodeBeam.MudExtensions/Components/TextFieldExtended/MudTextFieldExtended.razor

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,13 @@
5555
Pattern="@Pattern"
5656
AdornmentStart="@AdornmentStart"
5757
AdornmentEnd="@AdornmentEnd"
58-
AutoSize="AutoSize" />
58+
AutoSize="AutoSize"
59+
ForceShrink="@ForceShrink">
60+
<DataVisualiser>
61+
@DataVisualiser
62+
</DataVisualiser>
63+
64+
</MudInputExtended>
5965
}
6066
else
6167
{

CodeBeam.MudExtensions/Components/TextFieldExtended/MudTextFieldExtended.razor.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ public partial class MudTextFieldExtended<T> : MudDebouncedInputExtended<T>
2525
/// </summary>
2626
[Parameter] public bool AutoSize { get; set; }
2727

28+
/// <summary>
29+
/// The render fragment for child content.
30+
/// </summary>
31+
[Parameter] public RenderFragment DataVisualiser { get; set; }
32+
2833
/// <summary>
2934
/// Type of the input element. It should be a valid HTML5 input type.
3035
/// </summary>

ComponentViewer.Docs/Pages/Components/ApiPage.razor

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,27 @@
2424
</MudTable>
2525
</ExampleCard>
2626

27+
<ExampleCard Title="Api - MudChipField" HasExpansionPanel="true">
28+
<MudTable Items="@(typeof(MudChipField<string>).GetProperties().Where(x => x.Name != "FieldId" && x.Name != "UserAttributes").OrderBy(x => x.Name).ToList())">
29+
<HeaderContent>
30+
<MudTh>Name</MudTh>
31+
<MudTh>Type</MudTh>
32+
<MudTh>Default</MudTh>
33+
</HeaderContent>
34+
<RowTemplate>
35+
<MudTd>@context.Name</MudTd>
36+
<MudTd>@context.PropertyType.Name</MudTd>
37+
<MudTd>
38+
@if (true)
39+
{
40+
MudChipField<string> instance = new();
41+
<MudText Typo="Typo.body2">@(context.GetValue(instance)?.ToString() ?? "null")</MudText>
42+
}
43+
</MudTd>
44+
</RowTemplate>
45+
</MudTable>
46+
</ExampleCard>
47+
2748
<ExampleCard Title="Api - MudCodeInput" HasExpansionPanel="true">
2849
<MudTable Items="@(typeof(MudCodeInput<string>).GetProperties().Where(x => x.Name != "FieldId" && x.Name != "UserAttributes").OrderBy(x => x.Name).ToList())">
2950
<HeaderContent>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@page "/mudchipfield"
2+
@using ComponentViewer.Docs.Pages.Examples
3+
4+
<ExamplePage Title="MudChipField">
5+
<ExampleCard ExampleName="ChipFieldExample1" Title="Playground" Description="Chip field create chips when user press delimiter key.">
6+
<ChipFieldExample1 />
7+
</ExampleCard>
8+
</ExamplePage>
9+
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
@using Microsoft.AspNetCore.Components
2+
@using MudBlazor.Extensions
3+
4+
<MudGrid>
5+
<MudItem xs="12" sm="8" Class="d-flex flex-column gap-8 align-center justify-center">
6+
<MudChipField T="string" @bind-Value="_value" @bind-Values="_values" StyleChip="@(_disableRadius ? "border-radius: 0 !important" : null)" Delimiter="@_delimiter" FullWidth="true" Disabled="_disabled" ReadOnly="_readonly"
7+
ChipColor="_color" ChipVariant="_chipVariant" ChipSize="_chipSize" WrapChips="_wrapChips" MaxChips="_maxChips" ChipsMaxWidth="_chipsMaxWidth" Closeable="_closeable" Variant="_variant" Label="ChipField" />
8+
</MudItem>
9+
10+
<MudItem xs="12" sm="4">
11+
<MudStack Spacing="2">
12+
<MudText>Value: @_value</MudText>
13+
<MudText>Values:
14+
@foreach (var item in _values ?? new List<string>())
15+
{
16+
<MudText Inline="true"> @(" " + item + " ") </MudText>
17+
}
18+
</MudText>
19+
<MudTextField @bind-Value="@_delimiter" Immediate="true" Label="Delimiter" Variant="Variant.Outlined" Margin="Margin.Dense" />
20+
<MudNumericField @bind-Value="_maxChips" Label="MaxChips" Variant="Variant.Outlined" Margin="Margin.Dense" />
21+
<MudNumericField @bind-Value="_chipsMaxWidth" Label="ChipsMaxWidth" Variant="Variant.Outlined" Margin="Margin.Dense" />
22+
<MudSelect @bind-Value="_color" Variant="Variant.Outlined" Label="Color" Margin="Margin.Dense" Dense="true">
23+
@foreach (var item in Enum.GetValues<Color>())
24+
{
25+
<MudSelectItem Value="item">@item.ToDescriptionString()</MudSelectItem>
26+
}
27+
</MudSelect>
28+
<MudSelect @bind-Value="_chipVariant" Variant="Variant.Outlined" Label="Chip Variant" Margin="Margin.Dense" Dense="true">
29+
@foreach (var item in Enum.GetValues<Variant>())
30+
{
31+
<MudSelectItem Value="item">@item.ToDescriptionString()</MudSelectItem>
32+
}
33+
</MudSelect>
34+
<MudSelect @bind-Value="_variant" Variant="Variant.Outlined" Label="Variant" Margin="Margin.Dense" Dense="true">
35+
@foreach (var item in Enum.GetValues<Variant>())
36+
{
37+
<MudSelectItem Value="item">@item.ToDescriptionString()</MudSelectItem>
38+
}
39+
</MudSelect>
40+
<MudSelect @bind-Value="_chipSize" Variant="Variant.Outlined" Label="ChipSize" Margin="Margin.Dense" Dense="true">
41+
@foreach (var item in Enum.GetValues<Size>())
42+
{
43+
<MudSelectItem Value="item">@item.ToDescriptionString()</MudSelectItem>
44+
}
45+
</MudSelect>
46+
<MudSwitchM3 @bind-Checked="@_wrapChips" Label="WrapChips" Color="Color.Primary" />
47+
<MudSwitchM3 @bind-Checked="@_disabled" Label="Disabled" Color="Color.Primary" />
48+
<MudSwitchM3 @bind-Checked="@_readonly" Label="ReadOnly" Color="Color.Primary" />
49+
<MudSwitchM3 @bind-Checked="@_disableRadius" Label="Disable Border Radius" Color="Color.Primary" />
50+
<MudSwitchM3 @bind-Checked="@_closeable" Label="Closeable" Color="Color.Primary" />
51+
</MudStack>
52+
</MudItem>
53+
</MudGrid>
54+
55+
@code{
56+
char _delimiter = ' ';
57+
string _value;
58+
List<string> _values;
59+
MudCodeInput<string> _textFieldGroup;
60+
int _maxChips = 0;
61+
int _chipsMaxWidth = 80;
62+
Color _color = Color.Default;
63+
Variant _chipVariant = Variant.Filled;
64+
Variant _variant = Variant.Text;
65+
Size _chipSize = Size.Medium;
66+
bool _wrapChips;
67+
bool _disabled;
68+
bool _readonly;
69+
bool _disableRadius;
70+
bool _closeable = true;
71+
}

0 commit comments

Comments
 (0)