Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,18 @@
<param name="e"></param>
<returns></returns>
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.InputHelpers`1.GetMaxValue">
<summary>
Because of the limitation of the web component, the maximum value is set to 9999999999 for really large numbers.
</summary>
<returns>The maximum value for the underlying type</returns>
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.InputHelpers`1.GetMinValue">
<summary>
Because of the limitation of the web component, the minimum value is set to -9999999999 for really large negative numbers.
</summary>
<returns>The minimum value for the underlying type</returns>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentBodyContent.ChildContent">
<summary>
Gets or sets the content to be rendered inside the component.
Expand Down Expand Up @@ -7670,6 +7682,12 @@
Gets or sets the content to be rendered inside the component.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentNumberField`1.UseTypeConstraints">
<summary>
If true, the min and max values will be automatically set based on the type of TValue,
unless an explicit value for Min or Max is provided.
</summary>
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.FluentNumberField`1.FormatValueAsString(`0)">
<summary>
Formats the value as a string. Derived classes can override this to determine the formatting used for <c>CurrentValueAsString</c>.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<p>
<FluentNumberField @bind-Value="@exampleUshort1" UseTypeConstraints>Unsigned short with inherent constraints from type</FluentNumberField>
Example unsigned short: @exampleUshort1
<br/>
Minimum value: @(ushort.MinValue); Maximum value: @(ushort.MaxValue)
</p>

<p>
<FluentNumberField @bind-Value="@exampleUshort2" Max="10" UseTypeConstraints>Unsigned short with inherent constraints from type and manual max</FluentNumberField>
Example unsigned short: @exampleUshort2
<br/>
Minimum value: @(ushort.MinValue); Maximum value: 10
</p>

<p>
<FluentNumberField @bind-Value="@exampleUshort3" Min="5" Max="10" UseTypeConstraints>Unsigned short with inherent constraints, but Min and Max overrides.</FluentNumberField>
Example unsigned short: @exampleUshort3
<br/>
Minimum value: 5; Maximum value: 10
</p>

@code {
ushort exampleUshort1 { get; set; }
ushort exampleUshort2 { get; set; }
ushort exampleUshort3 { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,46 +1,77 @@
ο»Ώ<p>
<FluentNumberField @bind-Value="exampleLong">Long</FluentNumberField><br />
<FluentNumberField @bind-Value="exampleLong">Long</FluentNumberField>
<br/>
Example long: @exampleLong
<br />
Minimum value: -999999999999; Maximum value: 999999999999
<br/>
Minimum value: @(MinValue); Maximum value: @(MaxValue)
</p>
<p>
<FluentNumberField @bind-Value="shortMin">Short</FluentNumberField>
<br />
<br/>
Minimum value: @(short.MinValue); Maximum value: @(short.MaxValue)
</p>

<p>
<FluentNumberField @bind-Value="@exampleFloat">Float</FluentNumberField><br />
<FluentNumberField @bind-Value="@exampleFloat">Float</FluentNumberField>
<br/>
Example float: @exampleFloat
<br />
Minimum value: @(float.MinValue); Maximum value: @(float.MaxValue)
<br/>
Minimum value: @(MinValue); Maximum value: @(MaxValue)
</p>
<p>
<FluentNumberField Step=0.25 @bind-Value="@exampleFloat">Float</FluentNumberField><br />
Example float: @exampleFloat (step=0.25)
<br />
Minimum value: @(float.MinValue); Maximum value: @(float.MaxValue)
<FluentNumberField Step=0.25 @bind-Value="@exampleFloat2">Float</FluentNumberField>
<br/>
Example float: @exampleFloat2 (step=0.25)
<br/>
Minimum value: @(MinValue); Maximum value: @(MaxValue)
</p>
<p>
<FluentNumberField @bind-Value="@exampleDouble" >Double</FluentNumberField><br />
<FluentNumberField @bind-Value="@exampleDouble">Double</FluentNumberField>
<br/>
Example double: @exampleDouble
<br />
Minimum value: @(double.MinValue); Maximum value: @(double.MaxValue)
<br/>
Minimum value: @(MinValue); Maximum value: @(MaxValue)
</p>
<p>
<FluentNumberField @bind-Value="@exampleDecimal">Decimal</FluentNumberField><br />
<FluentNumberField @bind-Value="@exampleDecimal">Decimal</FluentNumberField>
<br/>
Example decimal: @exampleDecimal
<br />
Minimum value: @(decimal.MinValue); Maximum value: @(decimal.MaxValue)
<br/>
Minimum value: @(MinValue); Maximum value: @(MaxValue)
</p>

<p>
<FluentNumberField @bind-Value="@exampleUshort">Unsigned short</FluentNumberField>
Example unsigned short: @exampleUshort
<br/>
Minimum value: @(ushort.MinValue); Maximum value: @(ushort.MaxValue)
</p>

<p>
<FluentNumberField @bind-Value="@exampleUint">Unsigned integer</FluentNumberField>
Example unsigned integer: @exampleUint
<br/>
Minimum value: @(uint.MinValue); Maximum value: @(uint.MaxValue)
</p>

<p>
<FluentNumberField @bind-Value="@exampleUlong">Unsigned long</FluentNumberField>
Example unsigned long: @exampleUlong
<br/>
Minimum value: @(ulong.MinValue); Maximum value: @(MaxValue)
</p>

@code {
int exampleInt { get; set; } = 123;
int exampleInt2 { get; set; } = 345;
short shortMin = short.MinValue;
long exampleLong { get; set; } = 999999999999;
long exampleLong { get; set; } = 9999999997;
float exampleFloat { get; set; } = 123.45f;
float exampleFloat2 { get; set; } = 123.45f;
double exampleDouble { get; set; } = 456.32d;
decimal exampleDecimal { get; set; } = Decimal.One / 3;
ushort exampleUshort { get; set; }
uint exampleUint { get; set; }
ulong exampleUlong { get; set; }

private const long MaxValue = 9999999999;
private const long MinValue = -9999999999;
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

<DemoSection Title="Types" Component="@typeof(NumberFieldTypes)"></DemoSection>

<DemoSection Title="Types with constraints" Component="typeof(NumberFieldTypeConstraints)"></DemoSection>

<DemoSection Title="Displays" Component="@typeof(NumberFieldDisplays)"></DemoSection>

<DemoSection Title="Icons"Component="@typeof(NumberFieldIcons)"></DemoSection>
Expand Down
7 changes: 6 additions & 1 deletion src/Core/Components/Base/FluentInputBaseHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ protected virtual async Task ChangeHandlerAsync(ChangeEventArgs e)
{
await SetCurrentValueAsync(result ?? default);
_notifyCalled = true;

if(FieldBound && CascadedEditContext != null)
{
_parsingValidationMessages?.Clear(); // Clear any previous errors
}
}
else
{
Expand All @@ -56,7 +61,7 @@ protected virtual async Task ChangeHandlerAsync(ChangeEventArgs e)
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
protected virtual async Task InputHandlerAsync(ChangeEventArgs e) // TODO: To update in all Input fields
protected virtual async Task InputHandlerAsync(ChangeEventArgs e) // TODO: To update in all Input fields
{
if (!Immediate)
{
Expand Down
93 changes: 73 additions & 20 deletions src/Core/Components/Base/InputHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,25 @@ namespace Microsoft.FluentUI.AspNetCore.Components;

internal static class InputHelpers<TValue>
{
private const string WebComponentMaxValue = "9999999999";
private const string WebComponentMinValue = "-9999999999";
/// <summary>
/// Because of the limitation of the web component, the maximum value is set to 9999999999 for really large numbers.
/// </summary>
/// <returns>The maximum value for the underlying type</returns>
public static string GetMaxValue()
{
Type? targetType = Nullable.GetUnderlyingType(typeof(TValue)) ?? typeof(TValue);
TypeCode typeCode = Type.GetTypeCode(targetType);
var value = typeCode switch
{
TypeCode.Decimal => decimal.MaxValue.ToString(CultureInfo.InvariantCulture),
TypeCode.Double => double.MaxValue.ToString(CultureInfo.InvariantCulture),
TypeCode.Decimal => WebComponentMaxValue,
TypeCode.Double => WebComponentMaxValue,
TypeCode.Int16 => short.MaxValue.ToString(),
TypeCode.Int32 => int.MaxValue.ToString(),
TypeCode.Int64 => "999999999999",
TypeCode.SByte => sbyte.MaxValue.ToString(),
TypeCode.Single => float.MaxValue.ToString(CultureInfo.InvariantCulture),
TypeCode.Single => WebComponentMaxValue,
TypeCode.UInt16 => ushort.MaxValue.ToString(CultureInfo.InvariantCulture),
TypeCode.UInt32 => uint.MaxValue.ToString(),
TypeCode.UInt64 => "999999999999",
Expand All @@ -26,6 +32,10 @@ public static string GetMaxValue()
return value;
}

/// <summary>
/// Because of the limitation of the web component, the minimum value is set to -9999999999 for really large negative numbers.
/// </summary>
/// <returns>The minimum value for the underlying type</returns>
public static string GetMinValue()
{
Type? targetType = Nullable.GetUnderlyingType(typeof(TValue)) ?? typeof(TValue);
Expand All @@ -34,16 +44,16 @@ public static string GetMinValue()
var value = typeCode switch
{

TypeCode.Decimal => decimal.MinValue.ToString(CultureInfo.InvariantCulture),
TypeCode.Double => double.MinValue.ToString(CultureInfo.InvariantCulture),
TypeCode.Decimal => WebComponentMinValue,
TypeCode.Double => WebComponentMinValue,
TypeCode.Int16 => short.MinValue.ToString(),
TypeCode.Int32 => int.MinValue.ToString(),
TypeCode.Int64 => "-999999999999",
TypeCode.Int64 => WebComponentMinValue,
TypeCode.SByte => sbyte.MinValue.ToString(),
TypeCode.Single => float.MinValue.ToString(CultureInfo.InvariantCulture),
TypeCode.Single => WebComponentMinValue,
TypeCode.UInt16 => ushort.MinValue.ToString(CultureInfo.InvariantCulture),
TypeCode.UInt32 => uint.MinValue.ToString(),
TypeCode.UInt64 => "-999999999999",
TypeCode.UInt64 => ulong.MinValue.ToString(),
_ => ""

};
Expand Down Expand Up @@ -81,16 +91,6 @@ internal static void ValidateLongInputs(string? max, string? min)
{
throw new ArgumentException("Long Max value is smaller then Min value.");
}

if (maxValue > 999999999999)
{
throw new ArgumentException("Long Max value can not be bigger than 999999999999.");
}

if (minValue < -999999999999)
{
throw new ArgumentException("Long Min value can not be less than -999999999999.");
}
}

internal static void ValidateShortInputs(string? max, string? min)
Expand Down Expand Up @@ -137,12 +137,65 @@ internal static void ValidateDecimalInputs(string? max, string? min)
}
}

internal static void ValidateInputParameters(string? max, string? min)
internal static void ValidateUShortInputs(string max, string min)
{
var maxValue = Convert.ToUInt16(max);
var minValue = Convert.ToUInt16(min);

if (maxValue < minValue)
{
throw new ArgumentException("Unsigned Short Max value is smaller than Min value.");
}
}

internal static void ValidateUIntegerInputs(string max, string min)
{
var maxValue = Convert.ToUInt32(max);
var minValue = Convert.ToUInt32(min);

if (maxValue < minValue)
{
throw new ArgumentException("Unsigned integer Max value is smaller than Min value.");
}
}

internal static void ValidateULongInputs(string max, string min)
{
var maxValue = Convert.ToUInt64(max);
var minValue = Convert.ToUInt64(min);

if (maxValue < minValue)
{
throw new ArgumentException("Unsigned Long Max value is smaller than Min value.");
}
}

internal static void ValidateInputParameters(string? max, string? min)
{
if (max == null || min == null)
{
return; //nothing to validate
// No need to validate if either max or min is null
return;
}

if (typeof(TValue) == typeof(ushort))
{
ValidateUShortInputs(max, min);
}

if (typeof(TValue) == typeof(uint))
{
ValidateUIntegerInputs(max, min);
}

if (typeof(TValue) == typeof(ulong))
{
ValidateULongInputs(max, min);
}

if(typeof(TValue) == typeof(byte))
{
ValidateUShortInputs(max, min);
}

if (typeof(TValue) == typeof(sbyte))
Expand Down
5 changes: 2 additions & 3 deletions src/Core/Components/NumberField/FluentNumberField.razor
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
@inherits FluentInputBase<TValue>
@typeparam TValue where TValue : new()
@using System.Globalization;
@using System.Reflection;

@{
var value = BindConverter.FormatValue(CurrentValue, CultureInfo.InvariantCulture);
Expand All @@ -21,8 +20,8 @@
minlength="@MinLength"
size="@Size"
step=@Step
max="@(ReadOnly ? value : Max)"
min="@(ReadOnly ? value : Min)"
max="@(ReadOnly ? value : MaxValue)"
min="@(ReadOnly ? value : MinValue)"
id=@Id
value="@value"
disabled="@Disabled"
Expand Down
Loading
Loading