diff --git a/src/Connected.Components/Components/NumberInput.razor b/src/Connected.Components/Components/NumberInput.razor index c451fdf..70f581a 100644 --- a/src/Connected.Components/Components/NumberInput.razor +++ b/src/Connected.Components/Components/NumberInput.razor @@ -5,18 +5,18 @@ @typeparam NumberType
- - - + @onkeydown=@(args => ChangeValue(args)) + @onkeydown:preventDefault="@_preventDefaultAction" + @oninput=@GetValueAsync + @onmousewheel=@OnMouseWheel + @onwheel="OnMouseWheel" + @bind-value="@_value" + @attributes="@InputAttributes" /> @@ -34,6 +34,10 @@ } + + + + @if (Clearable && Value.ToString().Length > 0) { diff --git a/src/Connected.Components/Components/NumberInput.razor.cs b/src/Connected.Components/Components/NumberInput.razor.cs index 00c1d8b..3615c27 100644 --- a/src/Connected.Components/Components/NumberInput.razor.cs +++ b/src/Connected.Components/Components/NumberInput.razor.cs @@ -3,11 +3,11 @@ using Connected.Utilities; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using System.Numerics; -using static Connected.Colors; namespace Connected.Components; public partial class NumberInput:InputBase where NumberType : INumber { + private double _step =1; [Parameter] public double Step { @@ -22,30 +22,56 @@ public partial class NumberInput:InputBase where NumberType : INumbe } [Parameter] - public bool DisableMouseWheel { get; set; } = false; + public bool DisableMouseWheel + { + get; + set; + } = false; private async Task StepUp() { - double num = (double)Convert.ChangeType(Value, typeof(double)); - num += _step; - Value = AdjustDecimalPlaces((NumberType)Convert.ChangeType(num, typeof(NumberType))); + try + { + double num = (double)Convert.ChangeType(Value, typeof(double)); + num += _step; + if (DecimalPlaces > 0) + num = Math.Round(num, DecimalPlaces); + Value = (NumberType)Convert.ChangeType(num, typeof(NumberType)); + if (IsError) ErrorText = string.Empty; + } + catch + { + ErrorText = "Error with step up!"; + Value = default(NumberType); + } await ValueChanged.InvokeAsync(Value); } private async Task StepDown() { - double num = (double)Convert.ChangeType(Value, typeof(double)); - num -= _step; - Value = AdjustDecimalPlaces((NumberType)Convert.ChangeType(num, typeof(NumberType))); + try + { + double num = (double)Convert.ChangeType(Value, typeof(double)); + + num -= _step; + if (DecimalPlaces > 0) + num = Math.Round(num, DecimalPlaces); + Value = (NumberType)Convert.ChangeType(num, typeof(NumberType)); + if (IsError) ErrorText = string.Empty; + } catch + { + ErrorText = "Error with step down!"; + Value = default(NumberType); + } await ValueChanged.InvokeAsync(Value); } - protected async Task OnMouseWheel(WheelEventArgs obj) + protected async Task OnMouseWheel(WheelEventArgs args) { - if (DisableMouseWheel==false) + if (DisableMouseWheel == false) { - if (!obj.ShiftKey || Disabled || Readonly) + if (args.ShiftKey || Disabled || Readonly) return; - if (obj.DeltaY < 0) + if (args.DeltaY >= 0) { await StepDown(); } @@ -53,69 +79,136 @@ public partial class NumberInput:InputBase where NumberType : INumbe { await StepUp(); } + } else + { + return; } } + private string _value; [Parameter] - public NumberType Value + public NumberType? Value { - get; - set; + get + { + if (string.IsNullOrEmpty(_value)) return default(NumberType); + return (NumberType)Convert.ChangeType(_value, typeof(NumberType)); + } + set + { + _value = value.ToString(); + } } [Parameter] public int DecimalPlaces { get; set; } =0; - [Parameter] - public EventCallback ValueChanged { get; set; } + public EventCallback ValueChanged { get; set; } - public async Task ChangeValueAsync(ChangeEventArgs args) + public async Task GetValueAsync(ChangeEventArgs args) { if (args.Value is not null) { - NumberType value = (NumberType)Convert.ChangeType(args.Value, typeof(NumberType)); - if (value.ToString().Length <= 0) - { + string newVal = args.Value.ToString(); + if (!newVal.Equals("0")) + { + if (newVal.ToString().Contains("-")) + newVal = "-" + newVal.ToString().Replace("-", ""); + if (newVal.ToString().ToLower().Contains("e")) + newVal = "e" + newVal.ToString().Replace("e", ""); + } + if (string.IsNullOrEmpty(newVal)) + { + await ValueChanged.InvokeAsync((NumberType)Convert.ChangeType(AdjustDecimalPlaces((NumberType)Convert.ChangeType(null, typeof(NumberType))), typeof(NumberType))); + } + else + { + if (!newVal.Equals(_value)) + await ValueChanged.InvokeAsync((NumberType)Convert.ChangeType(AdjustDecimalPlaces((NumberType)Convert.ChangeType(newVal, typeof(NumberType))), typeof(NumberType))); + } + } + } - value = (NumberType)Convert.ChangeType(0, typeof(NumberType)); + [Parameter] public EventCallback OnKeyDown { get; set; } + + private bool CheckKey(string key) + { + bool result; + if (Helper.IsNumeric(key)) return true; + switch (key.ToLower()) + { + case "backspace": + case "delete": + case "arrowleft": + case "arrowright": + case "-": + //case "e": + { + result = true; + break; + } + default: + { + result = false; + break; } - await ValueChanged.InvokeAsync((NumberType)Convert.ChangeType(AdjustDecimalPlaces(value), typeof(NumberType))); } + + if ((key.Equals("-") || key.Equals("-")) && _value.Contains(key)) result = false; + return result; } - private NumberType AdjustDecimalPlaces(NumberType value) + private bool _preventDefaultAction = true; + public async Task ChangeValue(KeyboardEventArgs args) { - NumberType result = value; - if (Helper.NumberHasDecimalPlaces(value)) + _preventDefaultAction= true; + if (args is not null) { - if (DecimalPlaces > 0) + var key = args.Key.ToString().ToLower(); + if (CheckKey(key)) { - decimal rounded = (decimal)Convert.ChangeType(value, typeof(decimal)); - rounded = Math.Round(rounded, DecimalPlaces); - result = (NumberType)Convert.ChangeType(rounded, typeof(NumberType)); + _preventDefaultAction = false; + + await OnKeyDown.InvokeAsync(args); } + } else + { + args.Key = null; + } + } + + private NumberType AdjustDecimalPlaces(NumberType value) + { + var result = value; + if (DecimalPlaces > 0) + { + double converted = Math.Round((double)Convert.ChangeType(result, typeof(double)), DecimalPlaces); + return (NumberType)Convert.ChangeType(converted, typeof(NumberType)); } return result; } private async Task Clear() { + _value = string.Empty; await ValueChanged.InvokeAsync((NumberType)Convert.ChangeType(0, typeof(NumberType))); } - #region Lifecycle - - protected override async Task OnInitializedAsync() + protected override async Task OnAfterRenderAsync(bool firstRender) { - if (DecimalPlaces > 0) + if (firstRender) { - Value = AdjustDecimalPlaces(Value); - await ValueChanged.InvokeAsync(Value); + if (!DecimalPlaces.Equals(Helper.GetDecimalPlaces(Value))) + { + Value = AdjustDecimalPlaces(Value); + StateHasChanged(); + } } } + #region Lifecycle protected override async Task OnParametersSetAsync() { if (typeof(NumberType).Name.ToLower().Contains("int")) diff --git a/src/Connected.Components/Models/InputBase.cs b/src/Connected.Components/Models/InputBase.cs index 3bcd5fc..a95722c 100644 --- a/src/Connected.Components/Models/InputBase.cs +++ b/src/Connected.Components/Models/InputBase.cs @@ -1,5 +1,7 @@ using Connected.Utilities; using Microsoft.AspNetCore.Components; +using static Connected.Colors; +using static System.Net.Mime.MediaTypeNames; namespace Connected.Models; public class InputBase : ComponentBase @@ -71,6 +73,22 @@ public class InputBase : ComponentBase } } + /// + /// Fired when the text value changes. + /// + [Parameter] public EventCallback TextChanged { get; set; } + public string Text { get; set; } + + protected virtual async Task SetTextAsync(string text) + { + if (Text != text) + { + Text = text; + await TextChanged.InvokeAsync(text); + } + } + + private string _helperText = string.Empty; [Parameter] public string HelperText diff --git a/src/Connected.Components/Utilities/Helper.cs b/src/Connected.Components/Utilities/Helper.cs index 5737498..1b401ad 100644 --- a/src/Connected.Components/Utilities/Helper.cs +++ b/src/Connected.Components/Utilities/Helper.cs @@ -135,11 +135,11 @@ public static class Helper } } - public static bool IsVariableNumeric(string input) + public static bool IsNumeric(string input) { try { - var number = Decimal.Parse(input); + var number = Double.Parse(input); return true; } catch diff --git a/src/Connected.Components/Utilities/StyleBuilder.cs b/src/Connected.Components/Utilities/StyleBuilder.cs index 79c4b5b..620daab 100644 --- a/src/Connected.Components/Utilities/StyleBuilder.cs +++ b/src/Connected.Components/Utilities/StyleBuilder.cs @@ -10,6 +10,7 @@ namespace Connected.Utilities; public struct StyleBuilder { private string stringBuffer; + private string style; /// /// Creates a StyleBuilder used to define conditional in-line style used in a component. Call Build() to return the completed style as a string. @@ -35,6 +36,7 @@ public struct StyleBuilder /// /// public StyleBuilder(string prop, string value) => stringBuffer = $"{prop}:{value};"; + public StyleBuilder(string style) : this() => this.style = style; /// /// Adds a conditional in-line style to the builder with space separator and closing semicolon.