diff --git a/src/BlazorUI/Bit.BlazorUI.Tests/Components/Inputs/NumberField/BitNumberFieldTests.cs b/src/BlazorUI/Bit.BlazorUI.Tests/Components/Inputs/NumberField/BitNumberFieldTests.cs index c823e73408..7a4c0402a6 100644 --- a/src/BlazorUI/Bit.BlazorUI.Tests/Components/Inputs/NumberField/BitNumberFieldTests.cs +++ b/src/BlazorUI/Bit.BlazorUI.Tests/Components/Inputs/NumberField/BitNumberFieldTests.cs @@ -641,6 +641,7 @@ public void BitNumberFieldEnterKeyDownTest(double defaultValue, string min, stri parameters.Add(p => p.DefaultValue, defaultValue); parameters.Add(p => p.Max, max); parameters.Add(p => p.Min, min); + parameters.Add(p => p.Precision, 2); }); var input = component.Find("input"); diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/NumberField/BitNumberField.razor.cs b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/NumberField/BitNumberField.razor.cs index 83216980eb..74ebe47db2 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/NumberField/BitNumberField.razor.cs +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/NumberField/BitNumberField.razor.cs @@ -9,6 +9,7 @@ namespace Bit.BlazorUI; /// public partial class BitNumberField<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TValue> : BitTextInputBase { + private int _precision; private bool _hasFocus; private TValue _min = default!; private TValue _max = default!; @@ -212,6 +213,13 @@ public BitNumberField() /// [Parameter] public string? Placeholder { get; set; } + /// + /// How many decimal places the value should be rounded to. + /// + [Parameter] + [CallOnSet(nameof(OnSetPrecision))] + public int? Precision { get; set; } + /// /// Prefix displayed before the numeric field contents. This is not included in the value. /// Ensure a descriptive label is present to assist screen readers, as the value does not include the prefix. @@ -283,11 +291,15 @@ protected override void RegisterCssStyles() protected override async Task OnInitializedAsync() { + OnValueChanged += HandleOnValueChanged; + if (ValueHasBeenSet is false && DefaultValue is not null) { Value = DefaultValue; } + NormalizeValue(); + await base.OnInitializedAsync(); } @@ -302,6 +314,8 @@ protected override bool TryParseValueFromString(string? value, [MaybeNullWhen(fa { result = CheckMinAndMax(result); + result = Normalize(result); + parsingErrorMessage = null; return true; } @@ -608,12 +622,76 @@ private void OnSetStep() } } + private void OnSetPrecision() + { + _precision = Precision is not null ? Precision.Value : CalculatePrecision(); + } + + private TValue Normalize(TValue value) + { + if (value is double doubleValue) + { + return (TValue)Convert.ChangeType(Math.Round(doubleValue, _precision), typeof(TValue)); + } + else if (value is float floatValue) + { + return (TValue)Convert.ChangeType(Math.Round(floatValue, _precision), typeof(TValue)); + } + else if (value is decimal decimalValue) + { + return (TValue)Convert.ChangeType(Math.Round(decimalValue, _precision), typeof(TValue)); + } + + return value; + } + + private int CalculatePrecision() + { + var step = Step ?? _step?.ToString() ?? "1"; + var regex = new Regex(@"[1-9]([0]+$)|\.([0-9]*)"); + if (regex.IsMatch(step) is false) return 0; + + var matches = regex.Matches(step); + if (matches.Count == 0) return 0; + + var groups = matches[0].Groups; + if (groups[1] != null && groups[1].Length != 0) + { + return -groups[1].Length; + } + + if (groups[2] != null && groups[2].Length != 0) + { + return groups[2].Length; + } + + return 0; + } + + private void NormalizeValue() + { + if (Value is null) return; + + var val = Normalize(Value); + + if (EqualityComparer.Default.Equals(val, Value)) return; + + Value = val; + } + + private void HandleOnValueChanged(object? sender, EventArgs args) + { + NormalizeValue(); + } + protected override async ValueTask DisposeAsync(bool disposing) { if (IsDisposed || disposing is false) return; + OnValueChanged -= HandleOnValueChanged; + _continuousChangeValueCts?.Dispose(); await base.DisposeAsync(disposing); diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/NumberField/BitNumberFieldDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/NumberField/BitNumberFieldDemo.razor index 984c875293..809b96cfb6 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/NumberField/BitNumberFieldDemo.razor +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/NumberField/BitNumberFieldDemo.razor @@ -142,7 +142,15 @@ - + +
Specifies how many decimal places the value is rounded to.
+
+
+ +
+
+ +
Demonstrates hiding the input field in BitNumberField while still allowing value changes.

@@ -155,7 +163,7 @@
- +
Handle events in BitNumberField, including increment, decrement, and change events.

@@ -170,7 +178,7 @@
- +
Demonstrates validation for BitNumberField within a form, including required fields and custom validation messages.

@@ -192,7 +200,7 @@
- +
Explores styling and class customization for BitNumberField, including component styles, custom classes, and detailed style options.


@@ -223,7 +231,7 @@
- +
Use BitNumberField in right-to-left (RTL).

diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/NumberField/BitNumberFieldDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/NumberField/BitNumberFieldDemo.razor.cs index 88759b2799..2c7ea5e7a7 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/NumberField/BitNumberFieldDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/NumberField/BitNumberFieldDemo.razor.cs @@ -229,6 +229,13 @@ public partial class BitNumberFieldDemo Description = "Input placeholder text.", }, new() + { + Name = "Precision", + Type = "int?", + DefaultValue = "null", + Description = "How many decimal places the value should be rounded to.", + }, + new() { Name = "Prefix", Type = "string?", @@ -484,6 +491,8 @@ public partial class BitNumberFieldDemo private int hideInputValue; + private double precisionInputValue = 3.1415; + private string SuccessMessage = string.Empty; private BitNumberFieldValidationModel validationModel = new(); diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/NumberField/BitNumberFieldDemo.razor.samples.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/NumberField/BitNumberFieldDemo.razor.samples.cs index d5228f4abb..81434dd577 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/NumberField/BitNumberFieldDemo.razor.samples.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/NumberField/BitNumberFieldDemo.razor.samples.cs @@ -92,14 +92,19 @@ public partial class BitNumberFieldDemo private int minMaxValue;"; private readonly string example8RazorCode = @" +"; + private readonly string example8CsharpCode = @" + private double precisionInputValue = 3.1415;"; + + private readonly string example9RazorCode = @" "; - private readonly string example8CsharpCode = @" + private readonly string example9CsharpCode = @" private int hideInputValue;"; - private readonly string example9RazorCode = @" + private readonly string example10RazorCode = @" onIncrementCounter++"" OnDecrement=""(double v) => onDecrementCounter++"" /> @@ -108,12 +113,12 @@ public partial class BitNumberFieldDemo onChangeCounter++"" />
OnChange Counter: @onChangeCounter
"; - private readonly string example9CsharpCode = @" + private readonly string example10CsharpCode = @" private int onIncrementCounter; private int onDecrementCounter; private int onChangeCounter;"; - private readonly string example10RazorCode = @" + private readonly string example11RazorCode = @" @@ -122,7 +127,7 @@ public partial class BitNumberFieldDemo
Submit
"; - private readonly string example10CsharpCode = @" + private readonly string example11CsharpCode = @" public class BitNumberFieldValidationModel { [Required(ErrorMessage = ""Enter an age"")] @@ -132,7 +137,7 @@ public class BitNumberFieldValidationModel private BitNumberFieldValidationModel validationModel = new();"; - private readonly string example11RazorCode = @" + private readonly string example12RazorCode = @"