Compare commits
	
		
			3 Commits
		
	
	
		
			25606b926b
			...
			edcc8661e3
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					edcc8661e3 | ||
| 
						 | 
					b7db83fe15 | ||
| 
						 | 
					a04a0f07e2 | 
@ -143,7 +143,7 @@ public abstract class FormComponent<T, U> : UIComponent, IFormComponent, IDispos
 | 
				
			|||||||
	/// Return the validation error text or the conversion error message.
 | 
						/// Return the validation error text or the conversion error message.
 | 
				
			||||||
	/// </summary>
 | 
						/// </summary>
 | 
				
			||||||
	/// <returns>Error text/message</returns>
 | 
						/// <returns>Error text/message</returns>
 | 
				
			||||||
	 public string? GetErrorText()
 | 
						public string? GetErrorText(bool test = false)
 | 
				
			||||||
	 {
 | 
						 {
 | 
				
			||||||
		  // ErrorText is either set from outside or the first validation error
 | 
							  // ErrorText is either set from outside or the first validation error
 | 
				
			||||||
		  if (!IsNullOrWhiteSpace(ErrorText))
 | 
							  if (!IsNullOrWhiteSpace(ErrorText))
 | 
				
			||||||
@ -152,6 +152,8 @@ public abstract class FormComponent<T, U> : UIComponent, IFormComponent, IDispos
 | 
				
			|||||||
		  if (!IsNullOrWhiteSpace(ConversionErrorMessage))
 | 
							  if (!IsNullOrWhiteSpace(ConversionErrorMessage))
 | 
				
			||||||
				return ConversionErrorMessage;
 | 
									return ConversionErrorMessage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (test) return "Error: test";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		  return null;
 | 
							  return null;
 | 
				
			||||||
	 }
 | 
						 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,5 @@
 | 
				
			|||||||
using System.Timers;
 | 
					using System.Timers;
 | 
				
			||||||
using Connected.Annotations;
 | 
					using Connected.Annotations;
 | 
				
			||||||
using Connected.Utilities.BindingConverters;
 | 
					 | 
				
			||||||
using Microsoft.AspNetCore.Components;
 | 
					using Microsoft.AspNetCore.Components;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Connected.Components;
 | 
					namespace Connected.Components;
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,23 @@
 | 
				
			|||||||
@inherits InputBase<T>
 | 
					@inherits InputBase<T>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div class="@Classname">
 | 
					<div class="@Classname">
 | 
				
			||||||
 | 
					    <InputControl Label="@Label"
 | 
				
			||||||
 | 
					                  Variant="@Variant"
 | 
				
			||||||
 | 
					                  HelperText="@HelperText"
 | 
				
			||||||
 | 
					                  HelperTextOnFocus="@HelperTextOnFocus"
 | 
				
			||||||
 | 
					                  CounterText="@GetCounterText()"
 | 
				
			||||||
 | 
					                  FullWidth="@FullWidth"
 | 
				
			||||||
 | 
					                  Class="@Classname"
 | 
				
			||||||
 | 
					                  Error="@HasErrors"
 | 
				
			||||||
 | 
					                  ErrorText="@ErrorText"
 | 
				
			||||||
 | 
					                  ErrorId="@ErrorId"
 | 
				
			||||||
 | 
					                  Disabled="@Disabled"
 | 
				
			||||||
 | 
					                  Margin="@Margin"
 | 
				
			||||||
 | 
					                  Required="@Required"
 | 
				
			||||||
 | 
					                  ForId="@FieldId">
 | 
				
			||||||
 | 
					    <CascadingValue Name="SubscribeToParentForm" Value="@base.SubscribeToParentForm" IsFixed="true">
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@if (Adornment == Adornment.Start)
 | 
						@if (Adornment == Adornment.Start)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	    <InputAdornment Class="@AdornmentClassname" 
 | 
						    <InputAdornment Class="@AdornmentClassname" 
 | 
				
			||||||
@ -15,7 +32,7 @@
 | 
				
			|||||||
                AriaLabel="@AdornmentAriaLabel"
 | 
					                AriaLabel="@AdornmentAriaLabel"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					    <InputContent>
 | 
				
			||||||
	    @if (Lines > 1)
 | 
						    @if (Lines > 1)
 | 
				
			||||||
	    {
 | 
						    {
 | 
				
			||||||
	        <textarea class="@InputClassname"
 | 
						        <textarea class="@InputClassname"
 | 
				
			||||||
@ -46,6 +63,7 @@
 | 
				
			|||||||
            > 
 | 
					            > 
 | 
				
			||||||
                @Text
 | 
					                @Text
 | 
				
			||||||
            </textarea>
 | 
					            </textarea>
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
            @*Note: double mouse wheel handlers needed for Firefox because it doesn't know onmousewheel*@
 | 
					            @*Note: double mouse wheel handlers needed for Firefox because it doesn't know onmousewheel*@
 | 
				
			||||||
            @*note: the value="@_internalText" is absolutely essential here. the inner html @Text is needed by tests checking it*@
 | 
					            @*note: the value="@_internalText" is absolutely essential here. the inner html @Text is needed by tests checking it*@
 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
@ -104,15 +122,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	    @if (_showClearable && !Disabled)
 | 
						    @if (_showClearable && !Disabled)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
        <IconButton Class="@ClearButtonClassname"
 | 
					
 | 
				
			||||||
                    Color="@ThemeColor.Default" 
 | 
					 | 
				
			||||||
                    Icon="@ClearIcon" 
 | 
					 | 
				
			||||||
                    Size="@Size.Small" 
 | 
					 | 
				
			||||||
                    OnClick="@ClearButtonClickHandlerAsync"
 | 
					 | 
				
			||||||
                    tabindex="-1"
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	    @if (Adornment == Adornment.End)
 | 
						    @if (Adornment == Adornment.End)
 | 
				
			||||||
	    {
 | 
						    {
 | 
				
			||||||
	        <InputAdornment Class="@AdornmentClassname" 
 | 
						        <InputAdornment Class="@AdornmentClassname" 
 | 
				
			||||||
@ -142,4 +155,12 @@
 | 
				
			|||||||
                </Button>
 | 
					                </Button>
 | 
				
			||||||
	        </div>
 | 
						        </div>
 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        </InputContent>
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    </CascadingValue>  
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					    </InputControl>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -2,11 +2,191 @@
 | 
				
			|||||||
using Connected.Utilities;
 | 
					using Connected.Utilities;
 | 
				
			||||||
using Microsoft.AspNetCore.Components;
 | 
					using Microsoft.AspNetCore.Components;
 | 
				
			||||||
using Microsoft.AspNetCore.Components.Web;
 | 
					using Microsoft.AspNetCore.Components.Web;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					using System.Text.RegularExpressions;
 | 
				
			||||||
 | 
					using System.Timers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Connected.Components;
 | 
					namespace Connected.Components;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public partial class Input<T> : InputBase<T>
 | 
					public partial class Input<T> : InputBase<T>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Debounce
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// The current character counter, displayed below the text field.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						[Parameter] public string CounterText { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private System.Timers.Timer _timer;
 | 
				
			||||||
 | 
						private double _debounceInterval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Interval to be awaited in MILLISECONDS before changing the Text value
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						[Parameter]
 | 
				
			||||||
 | 
						public double TextChangeDelay
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get => _debounceInterval;
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (NumericConverter<double>.AreEqual(_debounceInterval, value))
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								_debounceInterval = value;
 | 
				
			||||||
 | 
								if (_debounceInterval == 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									// not debounced, dispose timer if any
 | 
				
			||||||
 | 
									ClearTimer(suppressTick: false);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								SetTimer();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// callback to be called when the debounce interval has elapsed
 | 
				
			||||||
 | 
						/// receives the Text as a parameter
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						[Parameter] public EventCallback<string> OnDebounceIntervalElapsed { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected Task OnDebounceChange()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (TextChangeDelay > 0 && _timer != null)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								_timer.Stop();
 | 
				
			||||||
 | 
								return base.UpdateValuePropertyAsync(false);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return Task.CompletedTask;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected override Task UpdateValuePropertyAsync(bool updateText)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// This method is called when Value property needs to be refreshed from the current Text property, so typically because Text property has changed.
 | 
				
			||||||
 | 
							// We want to debounce only text-input, not a value being set, so the debouncing is only done when updateText==false (because that indicates the
 | 
				
			||||||
 | 
							// change came from a Text setter)
 | 
				
			||||||
 | 
							if (updateText)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// we have a change coming not from the Text setter, no debouncing is needed
 | 
				
			||||||
 | 
								return base.UpdateValuePropertyAsync(updateText);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// if debounce interval is 0 we update immediately
 | 
				
			||||||
 | 
							if (TextChangeDelay <= 0 || _timer == null)
 | 
				
			||||||
 | 
								return base.UpdateValuePropertyAsync(updateText);
 | 
				
			||||||
 | 
							// If a debounce interval is defined, we want to delay the update of Value property.
 | 
				
			||||||
 | 
							_timer.Stop();
 | 
				
			||||||
 | 
							// restart the timer while user is typing
 | 
				
			||||||
 | 
							_timer.Start();
 | 
				
			||||||
 | 
							return Task.CompletedTask;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected override void OnParametersSet()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							base.OnParametersSet();
 | 
				
			||||||
 | 
							// if input is to be debounced, makes sense to bind the change of the text to oninput
 | 
				
			||||||
 | 
							// so we set Immediate to true
 | 
				
			||||||
 | 
							if (TextChangeDelay > 0)
 | 
				
			||||||
 | 
								Immediate = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void SetTimer()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (_timer == null)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								_timer = new System.Timers.Timer();
 | 
				
			||||||
 | 
								_timer.Elapsed += OnTimerTick;
 | 
				
			||||||
 | 
								_timer.AutoReset = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							_timer.Interval = TextChangeDelay;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void OnTimerTick(object sender, ElapsedEventArgs e)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							InvokeAsync(OnTimerTickGuiThread).AndForget();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private async Task OnTimerTickGuiThread()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							await base.UpdateValuePropertyAsync(false);
 | 
				
			||||||
 | 
							await OnDebounceIntervalElapsed.InvokeAsync(Text);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void ClearTimer(bool suppressTick = false)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (_timer == null)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							var wasEnabled = _timer.Enabled;
 | 
				
			||||||
 | 
							_timer.Stop();
 | 
				
			||||||
 | 
							_timer.Elapsed -= OnTimerTick;
 | 
				
			||||||
 | 
							_timer.Dispose();
 | 
				
			||||||
 | 
							_timer = null;
 | 
				
			||||||
 | 
							if (wasEnabled && !suppressTick)
 | 
				
			||||||
 | 
								OnTimerTickGuiThread().AndForget();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						*  Debounce end
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected CssBuilder CompiledHelperContainerClassList
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new CssBuilder("input-control-helper-container")
 | 
				
			||||||
 | 
								.AddClass($"px-1", Variant == Variant.Filled)
 | 
				
			||||||
 | 
								.AddClass($"px-2", Variant == Variant.Outlined)
 | 
				
			||||||
 | 
								.AddClass($"px-1", Variant == Variant.Text)
 | 
				
			||||||
 | 
								.AddClass(HelperContainerClassList);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// A space separated list of class names, added on top of the default helper container class list.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						[Parameter]
 | 
				
			||||||
 | 
						public string? HelperContainerClassList { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected CssBuilder CompiledHelperClassList
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new CssBuilder("input-helper-text")
 | 
				
			||||||
 | 
								.AddClass("input-helper-onfocus", HelperTextOnFocus)
 | 
				
			||||||
 | 
								.AddClass(HelperClassList);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// A space separated list of class names, added on top of the default helper class list.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						[Parameter]
 | 
				
			||||||
 | 
						public string? HelperClassList { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*protected string HelperContainer =>
 | 
				
			||||||
 | 
							new CssBuilder("input-control-helper-container")
 | 
				
			||||||
 | 
							.AddClass($"px-1", Variant == Variant.Filled)
 | 
				
			||||||
 | 
							.AddClass($"px-2", Variant == Variant.Outlined)
 | 
				
			||||||
 | 
							.Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected string HelperClass =>
 | 
				
			||||||
 | 
							new CssBuilder("input-helper-text")
 | 
				
			||||||
 | 
							 .AddClass("input-helper-onfocus", HelperTextOnFocus)
 | 
				
			||||||
 | 
							.Build();*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private string GetCounterText()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							string result = Text.Length.ToString();
 | 
				
			||||||
 | 
							if (string.IsNullOrEmpty(Text)) result = "0";
 | 
				
			||||||
 | 
							return result;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected string Classname => InputCssHelper.GetClassname(this,
 | 
						protected string Classname => InputCssHelper.GetClassname(this,
 | 
				
			||||||
      () => HasNativeHtmlPlaceholder() || !string.IsNullOrEmpty(Text) || Adornment == Adornment.Start || !string.IsNullOrWhiteSpace(Placeholder));
 | 
					      () => HasNativeHtmlPlaceholder() || !string.IsNullOrEmpty(Text) || Adornment == Adornment.Start || !string.IsNullOrWhiteSpace(Placeholder));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -31,15 +211,79 @@ public partial class Input<T> : InputBase<T>
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
   protected string InputTypeString => InputType.ToDescription();
 | 
					   protected string InputTypeString => InputType.ToDescription();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private bool IsDecimalNumber(string type)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							switch (type.ToLower())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								case "double":
 | 
				
			||||||
 | 
								case "float":
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private bool IsNumber(string s)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							bool result = false;
 | 
				
			||||||
 | 
							try
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								double d;
 | 
				
			||||||
 | 
								result= double.TryParse(s, out d);
 | 
				
			||||||
 | 
							} catch
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								result = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return result;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private string ValidateInput(string value)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							string result = value;
 | 
				
			||||||
 | 
							if (value is not null)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var expectedType = typeof(T).Name;
 | 
				
			||||||
 | 
								if (IsNumericType(expectedType))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (IsNumber(value.ToString()))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										result = value.ToString();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (IsDecimalNumber(value.ToString()))
 | 
				
			||||||
 | 
											result = Regex.Replace(value.ToString(), "[^0-9.]", "");
 | 
				
			||||||
 | 
										else result = Regex.Replace(value.ToString(), "[^0-9]", "");
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									result = value;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return result;
 | 
				
			||||||
 | 
						}*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected Task OnInput(ChangeEventArgs args)
 | 
						protected Task OnInput(ChangeEventArgs args)
 | 
				
			||||||
   {
 | 
					   {
 | 
				
			||||||
      if (!Immediate)
 | 
					      if (!Immediate)
 | 
				
			||||||
         return Task.CompletedTask;
 | 
					         return Task.CompletedTask;
 | 
				
			||||||
      _isFocused = true;
 | 
					      _isFocused = true;
 | 
				
			||||||
		return SetTextAsync(args?.Value as string);
 | 
							return SetTextAsync(args?.Value as string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   protected async Task OnChange(ChangeEventArgs args)
 | 
					   protected async Task OnChange(ChangeEventArgs args)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
							if (TextChangeDelay > 0 && _timer != null)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								_timer.Stop();
 | 
				
			||||||
 | 
								await UpdateValuePropertyAsync(false);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			_internalText = args?.Value as string;
 | 
								_internalText = args?.Value as string;
 | 
				
			||||||
			await OnInternalInputChanged.InvokeAsync(args);
 | 
								await OnInternalInputChanged.InvokeAsync(args);
 | 
				
			||||||
@ -49,6 +293,8 @@ public partial class Input<T> : InputBase<T>
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   /// <summary>
 | 
					   /// <summary>
 | 
				
			||||||
   /// Paste hook for descendants.
 | 
					   /// Paste hook for descendants.
 | 
				
			||||||
   /// </summary>
 | 
					   /// </summary>
 | 
				
			||||||
@ -164,12 +410,12 @@ public partial class Input<T> : InputBase<T>
 | 
				
			|||||||
         UpdateClearable(Text);
 | 
					         UpdateClearable(Text);
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   protected override async Task UpdateValuePropertyAsync(bool updateText)
 | 
					   /*protected override async Task UpdateValuePropertyAsync(bool updateText)
 | 
				
			||||||
   {
 | 
					   {
 | 
				
			||||||
      await base.UpdateValuePropertyAsync(updateText);
 | 
					      await base.UpdateValuePropertyAsync(updateText);
 | 
				
			||||||
      if (Clearable)
 | 
					      if (Clearable)
 | 
				
			||||||
         UpdateClearable(Value);
 | 
					         UpdateClearable(Value);
 | 
				
			||||||
   }
 | 
					   }*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   protected virtual async Task ClearButtonClickHandlerAsync(MouseEventArgs e)
 | 
					   protected virtual async Task ClearButtonClickHandlerAsync(MouseEventArgs e)
 | 
				
			||||||
   {
 | 
					   {
 | 
				
			||||||
@ -196,6 +442,33 @@ public partial class Input<T> : InputBase<T>
 | 
				
			|||||||
      {
 | 
					      {
 | 
				
			||||||
         // in WASM (or in BSS with TextUpdateSuppression==false) we always update
 | 
					         // in WASM (or in BSS with TextUpdateSuppression==false) we always update
 | 
				
			||||||
         _internalText = Text;
 | 
					         _internalText = Text;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							string baseTypeName = typeof(T).Name;
 | 
				
			||||||
 | 
							if (IsNumericType(baseTypeName) && InputType !=InputType.Number)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								InputType = InputType.Number;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private bool IsNumericType(string type)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							switch (type.ToLower())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								case "uint16":
 | 
				
			||||||
 | 
								case "uint32":
 | 
				
			||||||
 | 
								case "uint64":
 | 
				
			||||||
 | 
								case "int16":
 | 
				
			||||||
 | 
								case "int32":
 | 
				
			||||||
 | 
								case "int64":
 | 
				
			||||||
 | 
								case "int":
 | 
				
			||||||
 | 
								case "double":
 | 
				
			||||||
 | 
								case "decimal":
 | 
				
			||||||
 | 
								case "float":
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -220,6 +220,7 @@ public abstract class InputBase<T> : FormComponent<T, string>
 | 
				
			|||||||
            await UpdateValuePropertyAsync(false);
 | 
					            await UpdateValuePropertyAsync(false);
 | 
				
			||||||
         await TextChanged.InvokeAsync(Text);
 | 
					         await TextChanged.InvokeAsync(Text);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
							
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   /// <summary>
 | 
					   /// <summary>
 | 
				
			||||||
@ -329,7 +330,11 @@ public abstract class InputBase<T> : FormComponent<T, string>
 | 
				
			|||||||
   /// Fired when the Value property changes.
 | 
					   /// Fired when the Value property changes.
 | 
				
			||||||
   /// </summary>
 | 
					   /// </summary>
 | 
				
			||||||
   [Parameter]
 | 
					   [Parameter]
 | 
				
			||||||
   public EventCallback<T> ValueChanged { get; set; }
 | 
					   public EventCallback<T> ValueChanged
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get;
 | 
				
			||||||
 | 
							set;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   /// <summary>
 | 
					   /// <summary>
 | 
				
			||||||
   /// The value of this input element.
 | 
					   /// The value of this input element.
 | 
				
			||||||
 | 
				
			|||||||
@ -387,7 +387,7 @@ public partial class Picker<T> : FormComponent<T, string>
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
   protected override void ResetValue()
 | 
					   protected override void ResetValue()
 | 
				
			||||||
   {
 | 
					   {
 | 
				
			||||||
      _inputReference?.Reset();
 | 
					      _inputReference?.InputReference.Reset();
 | 
				
			||||||
      base.ResetValue();
 | 
					      base.ResetValue();
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,15 +1,15 @@
 | 
				
			|||||||
@namespace Connected.Components
 | 
					@namespace Connected.Components
 | 
				
			||||||
@typeparam T
 | 
					@typeparam T
 | 
				
			||||||
@inherits DebouncedInput<T>
 | 
					@inherits InputBase<T>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<CascadingValue Name="SubscribeToParentForm" Value="@SubscribeToParentForm" IsFixed="true">
 | 
					<CascadingValue Name="SubscribeToParentForm" Value="@base.SubscribeToParentForm" IsFixed="true">
 | 
				
			||||||
    <InputControl Label="@Label"
 | 
					    <InputControl Label="@Label"
 | 
				
			||||||
                     Variant="@Variant"
 | 
					                     Variant="@Variant"
 | 
				
			||||||
                     HelperText="@HelperText"
 | 
					                     HelperText="@HelperText"
 | 
				
			||||||
                     HelperTextOnFocus="@HelperTextOnFocus"
 | 
					                     HelperTextOnFocus="@HelperTextOnFocus"
 | 
				
			||||||
                     CounterText="@GetCounterText()"
 | 
					                     CounterText="@GetCounterText()"
 | 
				
			||||||
                     FullWidth="@FullWidth"
 | 
					                     FullWidth="@FullWidth"
 | 
				
			||||||
                     Class="@ClassList"
 | 
					                     class="@ClassList"
 | 
				
			||||||
                     Error="@HasErrors"
 | 
					                     Error="@HasErrors"
 | 
				
			||||||
                     ErrorText="@GetErrorText()"
 | 
					                     ErrorText="@GetErrorText()"
 | 
				
			||||||
                     ErrorId="@ErrorId"
 | 
					                     ErrorId="@ErrorId"
 | 
				
			||||||
@ -48,7 +48,6 @@
 | 
				
			|||||||
                              Margin="@Margin"
 | 
					                              Margin="@Margin"
 | 
				
			||||||
                              OnBlur="@OnBlurred"
 | 
					                              OnBlur="@OnBlurred"
 | 
				
			||||||
                              OnKeyDown="@InvokeKeyDown"
 | 
					                              OnKeyDown="@InvokeKeyDown"
 | 
				
			||||||
                              OnInternalInputChanged="OnChange"
 | 
					 | 
				
			||||||
                              OnKeyPress="@InvokeKeyPress"
 | 
					                              OnKeyPress="@InvokeKeyPress"
 | 
				
			||||||
                              OnKeyUp="@InvokeKeyUp"
 | 
					                              OnKeyUp="@InvokeKeyUp"
 | 
				
			||||||
                              KeyDownPreventDefault="KeyDownPreventDefault"
 | 
					                              KeyDownPreventDefault="KeyDownPreventDefault"
 | 
				
			||||||
@ -57,6 +56,7 @@
 | 
				
			|||||||
                              HideSpinButtons="true"
 | 
					                              HideSpinButtons="true"
 | 
				
			||||||
                              Clearable="@Clearable"
 | 
					                              Clearable="@Clearable"
 | 
				
			||||||
                              OnClearButtonClick="@OnClearButtonClick"
 | 
					                              OnClearButtonClick="@OnClearButtonClick"
 | 
				
			||||||
 | 
					                              Class="@CompiledClassList.Build()"
 | 
				
			||||||
                              Pattern="@Pattern"/>
 | 
					                              Pattern="@Pattern"/>
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
@ -83,8 +83,10 @@
 | 
				
			|||||||
                             OnAdornmentClick="@OnAdornmentClick"
 | 
					                             OnAdornmentClick="@OnAdornmentClick"
 | 
				
			||||||
                             Error="@HasError"
 | 
					                             Error="@HasError"
 | 
				
			||||||
                             Immediate="@Immediate"
 | 
					                             Immediate="@Immediate"
 | 
				
			||||||
                             Margin="@Margin" OnBlur="@OnBlurred"
 | 
					                             Margin="@Margin" 
 | 
				
			||||||
 | 
					                             OnBlur="@OnBlurred"
 | 
				
			||||||
                             Clearable="@Clearable"
 | 
					                             Clearable="@Clearable"
 | 
				
			||||||
 | 
					                              Class="@CompiledClassList.Build()"
 | 
				
			||||||
                             OnClearButtonClick="@OnClearButtonClick"/>
 | 
					                             OnClearButtonClick="@OnClearButtonClick"/>
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            </CascadingValue>
 | 
					            </CascadingValue>
 | 
				
			||||||
 | 
				
			|||||||
@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Components.Web;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Connected.Components;
 | 
					namespace Connected.Components;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public partial class TextField<T> : DebouncedInput<T>
 | 
					public partial class TextField<T> : InputBase<T>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    private Mask? _maskReference;
 | 
					    private Mask? _maskReference;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -19,7 +19,7 @@ public partial class TextField<T> : DebouncedInput<T>
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	internal override InputType GetInputType() => InputType;
 | 
						internal override InputType GetInputType() => InputType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private string GetCounterText() => Counter == null ? string.Empty : (Counter == 0 ? (string.IsNullOrEmpty(Text) ? "0" : $"{Text.Length}") : ((string.IsNullOrEmpty(Text) ? "0" : $"{Text.Length}") + $" / {Counter}"));
 | 
						private string GetCounterText() => base.Counter == null ? string.Empty : (base.Counter == 0 ? (string.IsNullOrEmpty(base.Text) ? "0" : $"{base.Text.Length}") : ((string.IsNullOrEmpty(base.Text) ? "0" : $"{base.Text.Length}") + $" / {base.Counter}"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// <summary>
 | 
						/// <summary>
 | 
				
			||||||
	/// Show clear button.
 | 
						/// Show clear button.
 | 
				
			||||||
@ -32,10 +32,25 @@ public partial class TextField<T> : DebouncedInput<T>
 | 
				
			|||||||
	/// </summary>
 | 
						/// </summary>
 | 
				
			||||||
	[Parameter] public EventCallback<MouseEventArgs> OnClearButtonClick { get; set; }
 | 
						[Parameter] public EventCallback<MouseEventArgs> OnClearButtonClick { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected string ClassList =>
 | 
					    /*protected string ClassList =>
 | 
				
			||||||
		new CssBuilder("input-input-control")
 | 
							new CssBuilder("input-input-control")
 | 
				
			||||||
		.AddClass(base.AdditionalClassList)
 | 
							.AddClass(base.AdditionalClassList)
 | 
				
			||||||
		.Build();
 | 
							.Build();*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected virtual CssBuilder CompiledClassList
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new CssBuilder("input-input-control")
 | 
				
			||||||
 | 
								.AddClass(ClassList);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// A space separated list of class names, added on top of the default class list.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						[Parameter]
 | 
				
			||||||
 | 
						public string? ClassList { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public override ValueTask FocusAsync()
 | 
						public override ValueTask FocusAsync()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -128,10 +143,10 @@ public partial class TextField<T> : DebouncedInput<T>
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		if (_mask != null)
 | 
							if (_mask != null)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var textValue = Converter.Convert(value);
 | 
								var textValue = base.Converter.Convert(value);
 | 
				
			||||||
			_mask.SetText(textValue);
 | 
								_mask.SetText(textValue);
 | 
				
			||||||
			textValue = Mask.GetCleanText();
 | 
								textValue = Mask.GetCleanText();
 | 
				
			||||||
			value = Converter.ConvertBack(textValue);
 | 
								value = base.Converter.ConvertBack(textValue);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return base.SetValueAsync(value, updateText);
 | 
							return base.SetValueAsync(value, updateText);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user