Skip to content

Commit 1b99c04

Browse files
danielchalmershenon
authored andcommitted
Inputs: Hide Clear button when readonly (MudBlazor#10070)
Co-authored-by: Meinrad Recheis <[email protected]>
1 parent f497f3f commit 1b99c04

File tree

19 files changed

+196
-46
lines changed

19 files changed

+196
-46
lines changed

src/MudBlazor.UnitTests/Components/DatePickerTests.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,20 +178,35 @@ public void DatePicker_Should_DateFormatTakesPrecedenceOverCulture()
178178
picker.Text.Should().Be("26 10 2020");
179179
}
180180

181+
[Test]
182+
public void ReadOnlyShouldNotHaveClearButton()
183+
{
184+
var comp = Context.RenderComponent<MudDatePicker>(p => p
185+
.Add(x => x.Text, "some value")
186+
.Add(x => x.Clearable, true)
187+
.Add(x => x.ReadOnly, false));
188+
189+
comp.FindAll(".mud-input-clear-button").Count.Should().Be(1);
190+
191+
comp.SetParametersAndRender(p => p.Add(x => x.ReadOnly, true)); //no clear button when readonly
192+
comp.FindAll(".mud-input-clear-button").Count.Should().Be(0);
193+
}
194+
181195
[Test]
182196
public void DatePicker_Should_Clear()
183197
{
184198
var comp = Context.RenderComponent<MudDatePicker>();
185199
// select elements needed for the test
186200
var picker = comp.Instance;
187-
picker.Text.Should().Be(null);
201+
picker.ReadOnly.Should().Be(false);
188202
picker.Date.Should().Be(null);
203+
picker.Text.Should().Be(null);
189204
comp.SetParam(p => p.Clearable, true);
190205
comp.SetParam(p => p.Date, new DateTime(2020, 10, 26));
191206
picker.Date.Should().Be(new DateTime(2020, 10, 26));
192207
picker.Text.Should().Be(new DateTime(2020, 10, 26).ToShortDateString());
193208

194-
comp.Find("button").Click(); //clear the input
209+
comp.Find(".mud-input-clear-button").Click(); //clear the input
195210

196211
picker.Text.Should().Be(""); //ensure the text and date are reset. Note this is an empty string rather than null due to how the reset works internally
197212
picker.Date.Should().Be(null);
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#pragma warning disable CS1998 // async without await
2+
3+
using System.ComponentModel.DataAnnotations;
4+
using System.Globalization;
5+
using System.Linq.Expressions;
6+
using Bunit;
7+
using FluentAssertions;
8+
using FluentValidation;
9+
using Microsoft.AspNetCore.Components;
10+
using Microsoft.AspNetCore.Components.Web;
11+
using MudBlazor.UnitTests.Dummy;
12+
using MudBlazor.UnitTests.TestComponents;
13+
using MudBlazor.UnitTests.TestComponents.Field;
14+
using MudBlazor.UnitTests.TestComponents.Form;
15+
using MudBlazor.UnitTests.TestComponents.TextField;
16+
using MudBlazor.UnitTests.Utilities;
17+
using NUnit.Framework;
18+
using static Bunit.ComponentParameterFactory;
19+
20+
namespace MudBlazor.UnitTests.Components
21+
{
22+
[TestFixture]
23+
public class InputTests : BunitTest
24+
{
25+
[Test]
26+
public void ReadOnlyShouldNotHaveClearButton()
27+
{
28+
var comp = Context.RenderComponent<MudInput<string>>(p => p
29+
.Add(x => x.Text, "some value")
30+
.Add(x => x.Clearable, true)
31+
.Add(x => x.ReadOnly, false));
32+
33+
comp.FindAll(".mud-input-clear-button").Count.Should().Be(1);
34+
35+
comp.SetParametersAndRender(p => p.Add(x => x.ReadOnly, true)); //no clear button when readonly
36+
comp.FindAll(".mud-input-clear-button").Count.Should().Be(0);
37+
}
38+
#nullable disable
39+
}
40+
}

src/MudBlazor.UnitTests/Components/MaskTests.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,5 +892,37 @@ public void RequiredAndAriaRequiredMaskWithMultipleLinesAttributes_Should_BeDyna
892892
comp.Find("textarea").HasAttribute("required").Should().BeTrue();
893893
comp.Find("textarea").GetAttribute("aria-required").Should().Be("true");
894894
}
895+
896+
[Test]
897+
public async Task ClearableReadOnlyMask_Should_NotHaveClearButton()
898+
{
899+
var comp = Context.RenderComponent<MudMask>();
900+
var maskField = comp.Instance;
901+
maskField.Clearable.Should().Be(false);
902+
maskField.ReadOnly.Should().Be(false);
903+
comp.SetParam(nameof(MudMask.Mask), new PatternMask("*00 000") { Placeholder = '_', CleanDelimiters = true });
904+
905+
// mask is not clearable, no clear button should show up
906+
comp.FindAll(".mud-input-clear-button").Count.Should().Be(0);
907+
908+
comp.SetParam(nameof(MudMask.Clearable), true);
909+
maskField.Clearable.Should().Be(true);
910+
911+
// mask is now clearable but contains no text so, no clear button should show up
912+
comp.FindAll(".mud-input-clear-button").Count.Should().Be(0);
913+
914+
await comp.InvokeAsync(async () => await maskField.FocusAsync());
915+
await comp.InvokeAsync(() => maskField.HandleKeyDown(new KeyboardEventArgs() { Key = "1" }));
916+
comp.WaitForAssertion(() => maskField.Text.Should().Be("1__ ___"));
917+
918+
// mask is clearable and contains text so the clear button should show up
919+
comp.FindAll(".mud-input-clear-button").Count.Should().Be(1);
920+
921+
comp.SetParam(nameof(MudMask.ReadOnly), true);
922+
923+
// mask is clearable and contains text but is readonly so the clear button should not show up
924+
comp.FindAll(".mud-input-clear-button").Count.Should().Be(0);
925+
926+
}
895927
}
896928
}

src/MudBlazor.UnitTests/Components/SelectTests.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,20 @@ public void Should_pass_various_aria_describedby_tests(
13721372

13731373
comp.Find(inputSelector).GetAttribute("aria-describedby").Should().Be(secondExpectedAriaDescribedBy);
13741374
}
1375+
1376+
[Test]
1377+
public void ReadOnlyShouldNotHaveClearButton()
1378+
{
1379+
var comp = Context.RenderComponent<MudSelect<string>>(p => p
1380+
.Add(x => x.Text, "some value")
1381+
.Add(x => x.Clearable, true)
1382+
.Add(x => x.ReadOnly, false));
1383+
1384+
comp.FindAll(".mud-input-clear-button").Count.Should().Be(1);
1385+
1386+
comp.SetParametersAndRender(p => p.Add(x => x.ReadOnly, true)); //no clear button when readonly
1387+
comp.FindAll(".mud-input-clear-button").Count.Should().Be(0);
1388+
}
13751389
#nullable disable
13761390
}
13771391
}

src/MudBlazor.UnitTests/Components/TextFieldTests.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1646,6 +1646,20 @@ public void Should_pass_various_aria_describedby_tests(
16461646

16471647
comp.Find(inputSelector).GetAttribute("aria-describedby").Should().Be(secondExpectedAriaDescribedBy);
16481648
}
1649+
1650+
[Test]
1651+
public void ReadOnlyShouldNotHaveClearButton()
1652+
{
1653+
var comp = Context.RenderComponent<MudTextField<string>>(p => p
1654+
.Add(x => x.Text, "some value")
1655+
.Add(x => x.Clearable, true)
1656+
.Add(x => x.ReadOnly, false));
1657+
1658+
comp.FindAll(".mud-input-clear-button").Count.Should().Be(1);
1659+
1660+
comp.SetParametersAndRender(p => p.Add(x => x.ReadOnly, true)); //no clear button when readonly
1661+
comp.FindAll(".mud-input-clear-button").Count.Should().Be(0);
1662+
}
16491663
#nullable disable
16501664
}
16511665
}

src/MudBlazor.UnitTests/Components/TimePickerTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,15 @@ public void TimePicker_Should_Clear()
5353
var comp = Context.RenderComponent<MudTimePicker>();
5454
// select elements needed for the test
5555
var picker = comp.Instance;
56+
picker.ReadOnly.Should().Be(false);
5657
picker.Text.Should().Be(null);
5758
picker.Time.Should().Be(null);
5859
comp.SetParam(p => p.Clearable, true);
5960
comp.SetParam(p => p.Time, new TimeSpan(637940935730000000));
6061
picker.Time.Should().Be(new TimeSpan(637940935730000000));
6162
picker.Text.Should().Be(new TimeSpan(637940935730000000).ToIsoString());
6263

63-
comp.Find("button").Click(); //clear the input
64+
comp.Find(".mud-input-clear-button").Click(); //clear the input
6465

6566
picker.Text.Should().Be(""); //ensure the text and time are reset. Note this is an empty string rather than null due to how the reset works internally
6667
picker.Time.Should().Be(null);

src/MudBlazor/Components/Autocomplete/MudAutocomplete.razor

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
HelperText="@HelperText"
3636
OnAdornmentClick="@AdornmentClickHandlerAsync" AdornmentIcon="@CurrentIcon" Adornment="@Adornment" AdornmentColor="@AdornmentColor" IconSize="@IconSize" AdornmentText="@AdornmentText"
3737
AdornmentAriaLabel="@AdornmentAriaLabel"
38-
Clearable="@(!GetReadOnlyState() && Clearable)" OnClearButtonClick="@OnClearButtonClick"
38+
Clearable="@(Clearable && !GetReadOnlyState())"
39+
OnClearButtonClick="@OnClearButtonClick"
3940
ClearIcon="@ClearIcon"
4041
MaxLength="@MaxLength"
4142
autocomplete="@GetAutocomplete()"

src/MudBlazor/Components/DatePicker/MudDateRangePicker.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
PlaceholderStart="@PlaceholderStart"
3535
PlaceholderEnd="@PlaceholderEnd"
3636
SeparatorIcon="@SeparatorIcon"
37-
Clearable="Clearable"
37+
Clearable="@(Clearable && !GetReadOnlyState())"
3838
Underline="@Underline" />
3939
</InputContent>
4040
</MudInputControl>;

src/MudBlazor/Components/Input/MudInput.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
}
106106
}
107107

108-
@if (GetClearable() && !GetDisabledState())
108+
@if (ShowClearButton())
109109
{
110110
<MudIconButton Class="@ClearButtonClassname"
111111
Color="@Color.Default"

src/MudBlazor/Components/Input/MudInput.razor.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ public partial class MudInput<T> : MudBaseInput<T>
3333

3434
protected string ClearButtonClassname =>
3535
new CssBuilder("mud-input-clear-button")
36-
.AddClass("me-n1", Adornment == Adornment.End && HideSpinButtons == false)
37-
.AddClass("mud-icon-button-edge-end", Adornment == Adornment.End && HideSpinButtons)
38-
.AddClass("me-6", Adornment != Adornment.End && HideSpinButtons == false)
39-
.AddClass("mud-icon-button-edge-margin-end", Adornment != Adornment.End && HideSpinButtons)
36+
.AddClass("me-n1", Adornment == Adornment.End && HideSpinButtons == false)
37+
.AddClass("mud-icon-button-edge-end", Adornment == Adornment.End && HideSpinButtons)
38+
.AddClass("me-6", Adornment != Adornment.End && HideSpinButtons == false)
39+
.AddClass("mud-icon-button-edge-margin-end", Adornment != Adornment.End && HideSpinButtons)
4040
.Build();
4141

4242
/// <summary>
@@ -224,15 +224,27 @@ public override ValueTask SelectRangeAsync(int pos1, int pos2)
224224
private Size GetButtonSize() => Margin == Margin.Dense ? Size.Small : Size.Medium;
225225

226226
/// <summary>
227-
/// If true, Clearable is true and there is a non null value (non-string for string values)
227+
/// Determine whether to show the clear button when Clearable==true.
228+
/// Of course the clear button won't show up if the text field is empty
228229
/// </summary>
229-
private bool GetClearable()
230+
private bool ShowClearButton()
230231
{
232+
if (GetDisabledState())
233+
{
234+
return false;
235+
}
236+
231237
if (!Clearable)
232238
{
233239
return false;
234240
}
235241

242+
// If this is a standalone input it will not be clearable when read-only
243+
if (SubscribeToParentForm && GetReadOnlyState())
244+
{
245+
return false;
246+
}
247+
236248
if (Value is string stringValue)
237249
{
238250
return !string.IsNullOrWhiteSpace(stringValue);

0 commit comments

Comments
 (0)