diff --git a/src/Connected.Components/Components/Alert/Alert.razor b/src/Connected.Components/Components/Alert/Alert.razor index 3da8dc8..8f72876 100644 --- a/src/Connected.Components/Components/Alert/Alert.razor +++ b/src/Connected.Components/Components/Alert/Alert.razor @@ -20,7 +20,7 @@ @if (CloseGlyphVisible) {
- +
} \ No newline at end of file diff --git a/src/Connected.Components/Components/Autocomplete/Autocomplete.razor b/src/Connected.Components/Components/Autocomplete/Autocomplete.razor index 627c8ea..74c7cfa 100644 --- a/src/Connected.Components/Components/Autocomplete/Autocomplete.razor +++ b/src/Connected.Components/Components/Autocomplete/Autocomplete.razor @@ -19,7 +19,7 @@ TextChanged="OnTextChanged" OnBlur="OnInputBlurred" OnKeyDown="@this.OnInputKeyDown" OnKeyUp="@this.OnInputKeyUp" autocomplete=@("disabled-"+Guid.NewGuid()) KeyUpPreventDefault="KeyUpPreventDefault" - Placeholder="@Placeholder" Immediate="true" + Placeholder="@Placeholder" ChangeTextImmediately="true" InputMode="@InputMode" Pattern="@Pattern" T="string" /> diff --git a/src/Connected.Components/Components/Button/GlyphButton.razor b/src/Connected.Components/Components/Button/IconButton.razor similarity index 74% rename from src/Connected.Components/Components/Button/GlyphButton.razor rename to src/Connected.Components/Components/Button/IconButton.razor index 76c20cd..93139d7 100644 --- a/src/Connected.Components/Components/Button/GlyphButton.razor +++ b/src/Connected.Components/Components/Button/IconButton.razor @@ -2,20 +2,20 @@ @inherits ButtonBase -@using Connected.Extensions; +@using Connected.Components; - @if (!String.IsNullOrEmpty(Glyph)) + @if (!String.IsNullOrEmpty(Icon)) { - + } else diff --git a/src/Connected.Components/Components/Button/GlyphButton.razor.cs b/src/Connected.Components/Components/Button/IconButton.razor.cs similarity index 86% rename from src/Connected.Components/Components/Button/GlyphButton.razor.cs rename to src/Connected.Components/Components/Button/IconButton.razor.cs index 51990d4..2755723 100644 --- a/src/Connected.Components/Components/Button/GlyphButton.razor.cs +++ b/src/Connected.Components/Components/Button/IconButton.razor.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Components; namespace Connected.Components; -public partial class GlyphButton : ButtonBase +public partial class IconButton : ButtonBase { /// /// Contains the default container classlist and the user defined classes. @@ -28,16 +28,16 @@ public partial class GlyphButton : ButtonBase #region Content placeholders /// - /// The Glyph that will be used in the component. + /// The Icon that will be used in the component. /// [Parameter] - public string? Glyph { get; set; } + public string? Icon { get; set; } /// /// GlyphTitle of the icon used for accessibility. /// [Parameter] - public string? GlyphTitle { get; set; } + public string? IconTitle { get; set; } #endregion #region Styling properties diff --git a/src/Connected.Components/Components/Button/ToggleGlyphButton.razor b/src/Connected.Components/Components/Button/ToggleIconButton.razor similarity index 53% rename from src/Connected.Components/Components/Button/ToggleGlyphButton.razor rename to src/Connected.Components/Components/Button/ToggleIconButton.razor index 545c071..1bd2f6c 100644 --- a/src/Connected.Components/Components/Button/ToggleGlyphButton.razor +++ b/src/Connected.Components/Components/Button/ToggleIconButton.razor @@ -2,12 +2,12 @@ @inherits UIComponent - diff --git a/src/Connected.Components/Components/Button/ToggleGlyphButton.razor.cs b/src/Connected.Components/Components/Button/ToggleIconButton.razor.cs similarity index 97% rename from src/Connected.Components/Components/Button/ToggleGlyphButton.razor.cs rename to src/Connected.Components/Components/Button/ToggleIconButton.razor.cs index 9ff05a0..0d42b0b 100644 --- a/src/Connected.Components/Components/Button/ToggleGlyphButton.razor.cs +++ b/src/Connected.Components/Components/Button/ToggleIconButton.razor.cs @@ -2,7 +2,7 @@ namespace Connected.Components; -public partial class ToggleGlyphButton : UIComponent +public partial class ToggleIconButton : UIComponent { #region EventCallbacks /// diff --git a/src/Connected.Components/Components/Carousel/Carousel.razor b/src/Connected.Components/Components/Carousel/Carousel.razor index 63830bf..aec618f 100644 --- a/src/Connected.Components/Components/Carousel/Carousel.razor +++ b/src/Connected.Components/Components/Carousel/Carousel.razor @@ -31,7 +31,7 @@ { @if (PreviousButtonTemplate == null) { - + } else { @@ -51,7 +51,7 @@ int current = i; if (BulletTemplate == null) { - + } else { @@ -69,7 +69,7 @@ { @if (NextButtonTemplate == null) { - + } else { diff --git a/src/Connected.Components/Components/Chip/Chip.razor b/src/Connected.Components/Components/Chip/Chip.razor index a720c9c..ae8bb21 100644 --- a/src/Connected.Components/Components/Chip/Chip.razor +++ b/src/Connected.Components/Components/Chip/Chip.razor @@ -27,7 +27,7 @@ } @if (OnClose.HasDelegate || ChipSet?.AllClosable==true) { - + } diff --git a/src/Connected.Components/Components/ColorPicker/ColorPicker.razor b/src/Connected.Components/Components/ColorPicker/ColorPicker.razor index 4d65251..a0b334b 100644 --- a/src/Connected.Components/Components/ColorPicker/ColorPicker.razor +++ b/src/Connected.Components/Components/ColorPicker/ColorPicker.razor @@ -12,12 +12,12 @@ @if (PickerVariant != PickerVariant.Static) { - + } - - - + + + @if (!DisableColorField) @@ -126,7 +126,7 @@ @if (!DisableModeSwitch) {
- +
} diff --git a/src/Connected.Components/Components/DataGrid/DataGrid.razor b/src/Connected.Components/Components/DataGrid/DataGrid.razor index 0f769fc..1ba89cf 100644 --- a/src/Connected.Components/Components/DataGrid/DataGrid.razor +++ b/src/Connected.Components/Components/DataGrid/DataGrid.razor @@ -128,8 +128,8 @@ + Icon="@(g.IsExpanded ? Icons.Material.Filled.ExpandMore : Icons.Material.Filled.ChevronRight)" + Clicked="@(() => ToggleGroupExpansion(g))" /> @if (GroupedColumn.GroupTemplate == null) { @@ -377,7 +377,7 @@ @if (column == null) { - + - - @*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*@ - } - else - { - - @*Note: double mouse wheel handlers needed for Firefox because it doesn't know onmousewheel*@ + + @if (NumberOfLines > 1) + { + + @*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*@ + } + else + { + + @*Note: double mouse wheel handlers needed for Firefox because it doesn't know onmousewheel*@ - @if (Disabled) { - @*Note: this div must always be there to avoid crashes in WASM, but it is hidden most of the time except if ChildContent should be shown. - In Disabled state the tabindex attribute must NOT be set at all or else it will get focus on click - *@ -
- @ChildContent -
- } - else - { - @*Note: this div must always be there to avoid crashes in WASM, but it is hidden most of the time except if ChildContent should be shown.*@ -
- @ChildContent -
- } + @if (Disabled) { + @*Note: this div must always be there to avoid crashes in WASM, but it is hidden most of the time except if ChildContent should be shown. + In Disabled state the tabindex attribute must NOT be set at all or else it will get focus on click + *@ +
+ @ChildContent +
+ } + else + { + @*Note: this div must always be there to avoid crashes in WASM, but it is hidden most of the time except if ChildContent should be shown.*@ +
+ @ChildContent +
} + } - @if (_showClearable && !Disabled) - { + @if (_showClearable && !Disabled) + { + + } - } - - - @if (Adornment == Adornment.End) - { - - } - - @if (Variant == Variant.Outlined) - { -
- } + Color="@AdornmentColor" + Size="@IconSize" + Text="@AdornmentText" + Edge="@Edge.End" + AdornmentClick="@OnAdornmentClick" + AriaLabel="@AdornmentAriaLabel" + /> + } - @if (!HideSpinButtons) - { -
- - -
- } + @if (Variant == Variant.Outlined) + { +
+ } - - - - - + @if (!HideSpinButtons) + { +
+ + +
+ } + diff --git a/src/Connected.Components/Components/Input/Input.razor.cs b/src/Connected.Components/Components/Input/Input.razor.cs index 234ef34..787d351 100644 --- a/src/Connected.Components/Components/Input/Input.razor.cs +++ b/src/Connected.Components/Components/Input/Input.razor.cs @@ -9,39 +9,18 @@ namespace Connected.Components; public partial class Input : InputBase { - /* - * Debounce - * - */ + #region Event Callbacks /// - /// The current character counter, displayed below the text field. + /// Paste hook for descendants. /// - [Parameter] public string CounterText { get; set; } - - private System.Timers.Timer _timer; - private double _debounceInterval; +#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously - /// - /// Interval to be awaited in MILLISECONDS before changing the Text value - /// - [Parameter] - public double TextChangeDelay + protected virtual async Task OnPaste(ClipboardEventArgs args) +#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously { - get => _debounceInterval; - set - { - if (NumericConverter.AreEqual(_debounceInterval, value)) - return; - _debounceInterval = value; - if (_debounceInterval == 0) - { - // not debounced, dispose timer if any - ClearTimer(suppressTick: false); - return; - } - SetTimer(); - } + // do nothing + return; } /// @@ -81,126 +60,232 @@ public partial class Input : InputBase return Task.CompletedTask; } - protected override void OnParametersSet() + private void OnTimerTick(object sender, ElapsedEventArgs e) { - 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; + InvokeAsync(OnTimerTickGuiThread).AndForget(); } - private void SetTimer() + private async Task OnTimerTickGuiThread() { - if (_timer == null) + await base.UpdateValuePropertyAsync(false); + await OnDebounceIntervalElapsed.InvokeAsync(Text); + } + protected Task OnInput(ChangeEventArgs args) + { + if (!ChangeTextImmediately) + return Task.CompletedTask; + _isFocused = true; + return SetTextAsync(args?.Value as string); + + } + + protected async Task OnChange(ChangeEventArgs args) + { + if (TextChangeDelay > 0 && _timer != null) { - _timer = new System.Timers.Timer(); - _timer.Elapsed += OnTimerTick; - _timer.AutoReset = false; + _timer.Stop(); + await UpdateValuePropertyAsync(false); } - _timer.Interval = TextChangeDelay; + else + { + _internalText = args?.Value as string; + await OnInternalInputChanged.InvokeAsync(args); + if (!ChangeTextImmediately) + { + await SetTextAsync(args?.Value as string); + } + } + } - private void OnTimerTick(object sender, ElapsedEventArgs e) + /// + /// Invokes the callback when the Up arrow button is clicked when the input is set to . + /// Note: use the optimized control if you need to deal with numbers. + /// + [Parameter] public EventCallback OnIncrement { get; set; } + + /// + /// Invokes the callback when the Down arrow button is clicked when the input is set to . + /// Note: use the optimized control if you need to deal with numbers. + /// + [Parameter] public EventCallback OnDecrement { get; set; } + + /// + /// Button click event for clear button. Called after text and value has been cleared. + /// + [Parameter] public EventCallback OnClearButtonClick { get; set; } + + /// + /// Mouse wheel event for input. + /// + [Parameter] public EventCallback OnMouseWheel { get; set; } + + public override async ValueTask FocusAsync() { - InvokeAsync(OnTimerTickGuiThread).AndForget(); + try + { + if (InputType == InputType.Hidden && ChildContent != null) + await _elementReference1.FocusAsync(); + else + await ElementReference.FocusAsync(); + } + catch (Exception e) + { + Console.WriteLine("Input.FocusAsync: " + e.Message); + } } - private async Task OnTimerTickGuiThread() + public override ValueTask BlurAsync() { - await base.UpdateValuePropertyAsync(false); - await OnDebounceIntervalElapsed.InvokeAsync(Text); + return ElementReference.BlurAsync(); } - private void ClearTimer(bool suppressTick = false) + public override ValueTask SelectAsync() { - if (_timer == null) - return; - var wasEnabled = _timer.Enabled; - _timer.Stop(); - _timer.Elapsed -= OnTimerTick; - _timer.Dispose(); - _timer = null; - if (wasEnabled && !suppressTick) - OnTimerTickGuiThread().AndForget(); + return ElementReference.SelectAsync(); } - /* - * Debounce end - */ + public override ValueTask SelectRangeAsync(int pos1, int pos2) + { + return ElementReference.SelectRangeAsync(pos1, pos2); + } - protected CssBuilder CompiledHelperContainerClassList + private void UpdateClearable(object value) { - 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(CompiledClearButtonClassList.Build()) - .AddClass(CompiledHelperClassList.Build()); - } + var showClearable = Clearable && ((value is string stringValue && !string.IsNullOrWhiteSpace(stringValue)) || (value is not string && value is not null)); + if (_showClearable != showClearable) + _showClearable = showClearable; } - protected CssBuilder CompiledClearButtonClassList + protected override async Task UpdateTextPropertyAsync(bool updateValue) { - get - { - return new CssBuilder() - .AddClass("me-n1", Adornment == Adornment.End && HideSpinButtons == false) - .AddClass("icon-button-edge-end", Adornment == Adornment.End && HideSpinButtons == true) - .AddClass("me-6", Adornment != Adornment.End && HideSpinButtons == false) - .AddClass("icon-button-edge-margin-end", Adornment != Adornment.End && HideSpinButtons == true); - } + await base.UpdateTextPropertyAsync(updateValue); + if (Clearable) + UpdateClearable(Text); + } + + protected virtual async Task ClearButtonClickHandlerAsync(MouseEventArgs e) + { + await SetTextAsync(string.Empty, updateValue: true); + await ElementReference.FocusAsync(); + await OnClearButtonClick.InvokeAsync(e); } /// - /// A space separated list of class names, added on top of the default helper container class list. + /// Custom input Attributes /// - [Parameter] - public string? HelperContainerClassList { get; set; } + [Parameter] public Dictionary? Attributes { get; set; } = null; + + #endregion + + + + #region Style properties - protected CssBuilder CompiledHelperClassList + /// + /// Type of the input element. It should be a valid HTML5 input type. + /// + [Parameter] public InputType InputType { get; set; } = InputType.Text; + + private string ClearIcon = Icons.Material.Filled.Clear; + + private string NumericUpIcon = Icons.Material.Filled.KeyboardArrowUp; + + private string NumericDownIcon = Icons.Material.Filled.KeyboardArrowDown; + + /// + /// Hides the spin buttons"/> + /// + [Parameter] public bool HideSpinButtons { get; set; } = true; + + /// + /// Show clear button. + /// + [Parameter] public bool Clearable { get; set; } = false; + + #region Wrapper class + [Parameter] + public string WrapperClass { get; set; } = string.Empty; + protected CssBuilder CompiledWrapperClass { get { - return new CssBuilder("input-helper-text") - .AddClass("input-helper-onfocus", HelperTextOnFocus) - .AddClass(HelperClassList); + return new CssBuilder("input") + .AddClass($"input-{Variant.ToDescription()}") + .AddClass($"input-adorned-{Adornment.ToDescription()}", Adornment != Adornment.None) + .AddClass($"input-margin-{Margin.ToDescription()}", when: () => Margin != Margin.None) + .AddClass("input-underline", when: () => DisableUnderLine == false && Variant != Variant.Outlined) + .AddClass("shrink", when: HasNativeHtmlPlaceholder() || !string.IsNullOrEmpty(Text) || Adornment == Adornment.Start || !string.IsNullOrWhiteSpace(Placeholder)) + .AddClass("disabled", Disabled) + .AddClass("input-error", HasErrors) + .AddClass("ltr", GetInputType() == InputType.Email || GetInputType() == InputType.Telephone) + .AddClass(WrapperClass); } } - /// - /// A space separated list of class names, added on top of the default helper class list. - /// - [Parameter] - public string? HelperClassList { get; set; } + #endregion - /*protected string HelperContainer => - new CssBuilder("input-control-helper-container") - .AddClass($"px-1", Variant == Variant.Filled) - .AddClass($"px-2", Variant == Variant.Outlined) - .Build(); + #region Input field class + [Parameter] + public string InputClass { get; set; } = string.Empty; + protected CssBuilder CompiledInputClass + { + get + { + return new CssBuilder("input-slot") + .AddClass("input-root") + .AddClass($"input-root-{Variant.ToDescription()}") + .AddClass($"input-root-adorned-{Adornment.ToDescription()}", Adornment != Adornment.None) + .AddClass($"input-root-margin-{Margin.ToDescription()}", when: () => Margin != Margin.None) + .AddClass(InputClass); + } + } + #endregion - protected string HelperClass => - new CssBuilder("input-helper-text") - .AddClass("input-helper-onfocus", HelperTextOnFocus) - .Build();*/ + #region Adornment class + [Parameter] + public string AdornmentClass { get; set; } = string.Empty; + protected CssBuilder CompiledAdornmentClass + { + get + { + return new CssBuilder("input-adornment") + .AddClass($"input-adornment-{Adornment.ToDescription()}", Adornment != Adornment.None) + .AddClass($"text", !string.IsNullOrEmpty(AdornmentText)) + .AddClass($"input-root-filled-shrink", Variant == Variant.Filled) + .AddClass(AdornmentClass); + } + } + #endregion - private string GetCounterText() + #region Clear icon class + [Parameter] + public string ClearButtonClass { get; set; } = string.Empty; + protected CssBuilder CompiledClearButtonClassList { - string result = Text.Length.ToString(); - if (string.IsNullOrEmpty(Text)) result = "0"; - return result; + get + { + return new CssBuilder() + .AddClass("me-n1", Adornment == Adornment.End && HideSpinButtons == false) + .AddClass("icon-button-edge-end", Adornment == Adornment.End && HideSpinButtons == true) + .AddClass("me-6", Adornment != Adornment.End && HideSpinButtons == false) + .AddClass("icon-button-edge-margin-end", Adornment != Adornment.End && HideSpinButtons == true) + .AddClass(ClearButtonClass); + } } + #endregion - protected string Classname => InputCssHelper.GetClassname(this, - () => HasNativeHtmlPlaceholder() || !string.IsNullOrEmpty(Text) || Adornment == Adornment.Start || !string.IsNullOrWhiteSpace(Placeholder)); + #region Helper container class - protected CssBuilder CompiledClassList + /// + /// A space separated list of class names, added on top of the default helper container class list. + /// + [Parameter] + public string? HelperContainerClass { get; set; } + protected CssBuilder CompiledHelperContainerClassList { get { @@ -208,304 +293,149 @@ public partial class Input : InputBase .AddClass($"px-1", Variant == Variant.Filled) .AddClass($"px-2", Variant == Variant.Outlined) .AddClass($"px-1", Variant == Variant.Text) - .AddClass(CompiledClearButtonClassList.Build()) - .AddClass(CompiledHelperClassList.Build()); + .AddClass(HelperContainerClass); } } - protected string InputClassname => InputCssHelper.GetInputClassname(this); + #endregion - protected string AdornmentClassname => InputCssHelper.GetAdornmentClassname(this); + #region Error container class -- still needs implementation + #endregion - /// - /// Type of the input element. It should be a valid HTML5 input type. - /// - [Parameter] public InputType InputType { get; set; } = InputType.Text; + #region Counter container class -- still needs implementation - internal override InputType GetInputType() => InputType; + #endregion - protected string InputTypeString => InputType.ToDescription(); + #endregion - /* - private bool IsDecimalNumber(string type) + + #region Content placeholders + + /// + /// The current character counter, displayed below the text field. + /// + [Parameter] public string CounterText { get; set; } + + private System.Timers.Timer _timer; + + private double _textChangeInterval; + + + /// + /// Interval to be awaited in MILLISECONDS before changing the Text value + /// + [Parameter] + public double TextChangeDelay { - switch (type.ToLower()) + get => _textChangeInterval; + set { - case "double": - case "float": - return true; - default: - return false; + if (NumericConverter.AreEqual(_textChangeInterval, value)) + return; + _textChangeInterval = value; + if (_textChangeInterval == 0) + { + // not debounced, dispose timer if any + ClearTimer(suppressTick: false); + return; + } + SetTimer(); } } - private bool IsNumber(string s) + private void SetTimer() { - bool result = false; - try - { - double d; - result= double.TryParse(s, out d); - } catch + if (_timer == null) { - result = false; + _timer = new System.Timers.Timer(); + _timer.Elapsed += OnTimerTick; + _timer.AutoReset = false; } - return result; + _timer.Interval = TextChangeDelay; } - private string ValidateInput(string value) + private void ClearTimer(bool suppressTick = false) { - 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; - }*/ - + if (_timer == null) + return; + var wasEnabled = _timer.Enabled; + _timer.Stop(); + _timer.Elapsed -= OnTimerTick; + _timer.Dispose(); + _timer = null; + if (wasEnabled && !suppressTick) + OnTimerTickGuiThread().AndForget(); + } - protected Task OnInput(ChangeEventArgs args) - { - if (!Immediate) - return Task.CompletedTask; - _isFocused = true; - return SetTextAsync(args?.Value as string); + /// + /// ChildContent of the MudInput will only be displayed if InputType.Hidden and if its not null. + /// + [Parameter] public RenderFragment ChildContent { get; set; } + private string TextCounter() + { + if (string.IsNullOrEmpty(Text)) return "0"; + return Text.Length.ToString(); } - protected async Task OnChange(ChangeEventArgs args) - { - if (TextChangeDelay > 0 && _timer != null) + [Parameter] + public double Step { get; set; } = 1; + internal override InputType GetInputType() => InputType; + protected string InputTypeString => InputType.ToDescription(); + public ElementReference ElementReference { get; private set; } + private ElementReference _elementReference1; + private Size GetButtonSize() => Margin == Margin.Dense ? Size.Small : Size.Medium; + private bool _showClearable; + private string _internalText; + + #endregion + + + + #region Lifecycle events + public override async Task SetParametersAsync(ParameterView parameters) + { + await base.SetParametersAsync(parameters); + //if (!_isFocused || _forceTextUpdate) + // _internalText = Text; + if (RuntimeLocation.IsServerSide && TextUpdateSuppression) { - _timer.Stop(); - await UpdateValuePropertyAsync(false); + // Text update suppression, only in BSS (not in WASM). + // This is a fix for #1012 + if (!_isFocused || _forceTextUpdate) + _internalText = Text; } else { - _internalText = args?.Value as string; - await OnInternalInputChanged.InvokeAsync(args); - if (!Immediate) - { - await SetTextAsync(args?.Value as string); - } + // in WASM (or in BSS with TextUpdateSuppression==false) we always update + _internalText = Text; } - - } - - /// - /// Paste hook for descendants. - /// -#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously - protected virtual async Task OnPaste(ClipboardEventArgs args) -#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously - { - // do nothing - return; - } - - /// - /// ChildContent of the MudInput will only be displayed if InputType.Hidden and if its not null. - /// - [Parameter] public RenderFragment ChildContent { get; set; } - - public ElementReference ElementReference { get; private set; } - private ElementReference _elementReference1; - - public override async ValueTask FocusAsync() - { - try - { - if (InputType == InputType.Hidden && ChildContent != null) - await _elementReference1.FocusAsync(); - else - await ElementReference.FocusAsync(); - } - catch (Exception e) - { - Console.WriteLine("Input.FocusAsync: " + e.Message); - } - } - - public override ValueTask BlurAsync() - { - return ElementReference.BlurAsync(); - } - - public override ValueTask SelectAsync() - { - return ElementReference.SelectAsync(); - } - - public override ValueTask SelectRangeAsync(int pos1, int pos2) - { - return ElementReference.SelectRangeAsync(pos1, pos2); - } - - /// - /// Invokes the callback when the Up arrow button is clicked when the input is set to . - /// Note: use the optimized control if you need to deal with numbers. - /// - [Parameter] public EventCallback OnIncrement { get; set; } - - /// - /// Invokes the callback when the Down arrow button is clicked when the input is set to . - /// Note: use the optimized control if you need to deal with numbers. - /// - [Parameter] public EventCallback OnDecrement { get; set; } - - /// - /// Hides the spin buttons for - /// - [Parameter] public bool HideSpinButtons { get; set; } = true; - - /// - /// Show clear button. - /// - [Parameter] public bool Clearable { get; set; } = false; - - /// - /// Button click event for clear button. Called after text and value has been cleared. - /// - [Parameter] public EventCallback OnClearButtonClick { get; set; } - - /// - /// Mouse wheel event for input. - /// - [Parameter] public EventCallback OnMouseWheel { get; set; } - - /// - /// Custom clear icon. - /// - [Parameter] public string ClearIcon { get; set; } = Icons.Material.Filled.Clear; - - /// - /// Custom numeric up icon. - /// - [Parameter] public string NumericUpIcon { get; set; } = Icons.Material.Filled.KeyboardArrowUp; - - /// - /// Custom numeric down icon. - /// - [Parameter] public string NumericDownIcon { get; set; } = Icons.Material.Filled.KeyboardArrowDown; - - private Size GetButtonSize() => Margin == Margin.Dense ? Size.Small : Size.Medium; - - private bool _showClearable; - - private void UpdateClearable(object value) - { - var showClearable = Clearable && ((value is string stringValue && !string.IsNullOrWhiteSpace(stringValue)) || (value is not string && value is not null)); - if (_showClearable != showClearable) - _showClearable = showClearable; - } - - protected override async Task UpdateTextPropertyAsync(bool updateValue) - { - await base.UpdateTextPropertyAsync(updateValue); - if (Clearable) - UpdateClearable(Text); - } - - /*protected override async Task UpdateValuePropertyAsync(bool updateText) - { - await base.UpdateValuePropertyAsync(updateText); - if (Clearable) - UpdateClearable(Value); - }*/ - - protected virtual async Task ClearButtonClickHandlerAsync(MouseEventArgs e) - { - await SetTextAsync(string.Empty, updateValue: true); - await ElementReference.FocusAsync(); - await OnClearButtonClick.InvokeAsync(e); - } - - private string _internalText; - - public override async Task SetParametersAsync(ParameterView parameters) - { - await base.SetParametersAsync(parameters); - //if (!_isFocused || _forceTextUpdate) - // _internalText = Text; - if (RuntimeLocation.IsServerSide && TextUpdateSuppression) - { - // Text update suppression, only in BSS (not in WASM). - // This is a fix for #1012 - if (!_isFocused || _forceTextUpdate) - _internalText = Text; - } - else - { - // in WASM (or in BSS with TextUpdateSuppression==false) we always update - _internalText = Text; - } - - string baseTypeName = typeof(T).Name; - if (IsNumericType(baseTypeName) && InputType !=InputType.Number) + if (Helper.IsNumericType(typeof(T).Name) && InputType != InputType.Number) { InputType = InputType.Number; } - } + } - private bool IsNumericType(string type) + protected override void OnParametersSet() { - 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; - } + base.OnParametersSet(); + // if input is to be debounced, makes sense to bind the change of the text to oninput + // so we set ChangeTextImmediately to true + if (TextChangeDelay > 0) + ChangeTextImmediately = true; } + #endregion + - /// - /// Sets the input text from outside programmatically - /// - /// - /// - public Task SetText(string text) - { - _internalText = text; - return SetTextAsync(text); - } - - - // Certain HTML5 inputs (dates and color) have a native placeholder - private bool HasNativeHtmlPlaceholder() - { - return GetInputType() is InputType.Color or InputType.Date or InputType.DateTimeLocal or InputType.Month - or InputType.Time or InputType.Week; - } -} + + + -public class InputString : Input { } + + + +} diff --git a/src/Connected.Components/Components/Input/InputAdornment.razor b/src/Connected.Components/Components/Input/InputAdornment.razor index 2b49c5f..14f746d 100644 --- a/src/Connected.Components/Components/Input/InputAdornment.razor +++ b/src/Connected.Components/Components/Input/InputAdornment.razor @@ -11,7 +11,7 @@ { @if (AdornmentClick.HasDelegate) { - + } else { diff --git a/src/Connected.Components/Components/Input/InputBase.cs b/src/Connected.Components/Components/Input/InputBase.cs index e95d4f9..571abc8 100644 --- a/src/Connected.Components/Components/Input/InputBase.cs +++ b/src/Connected.Components/Components/Input/InputBase.cs @@ -39,7 +39,7 @@ public abstract class InputBase : FormComponent /// [Parameter] [Category(CategoryTypes.FormComponent.Behavior)] - public bool Immediate { get; set; } + public bool ChangeTextImmediately { get; set; } = true; /// /// If true, the input will not have an underline. @@ -170,7 +170,7 @@ public abstract class InputBase : FormComponent /// [Parameter] [Category(CategoryTypes.FormComponent.Behavior)] - public int Lines { get; set; } = 1; + public int NumberOfLines { get; set; } = 1; /// /// The text to be displayed. diff --git a/src/Connected.Components/Components/Input/RangeInput.razor b/src/Connected.Components/Components/Input/RangeInput.razor index d38c193..bb3f56c 100644 --- a/src/Connected.Components/Components/Input/RangeInput.razor +++ b/src/Connected.Components/Components/Input/RangeInput.razor @@ -15,10 +15,10 @@ } - - @if (Adornment == Adornment.End) diff --git a/src/Connected.Components/Components/Mask/Mask.razor b/src/Connected.Components/Components/Mask/Mask.razor index 64d35a6..ebf52ce 100644 --- a/src/Connected.Components/Components/Mask/Mask.razor +++ b/src/Connected.Components/Components/Mask/Mask.razor @@ -58,7 +58,7 @@ Color="@ThemeColor.Default" Icon="@ClearIcon" Size="@Size.Small" - OnClick="@HandleClearButton"/> + Clicked="@HandleClearButton" /> } @if (Adornment == Adornment.End) diff --git a/src/Connected.Components/Components/Menu/Menu.razor b/src/Connected.Components/Components/Menu/Menu.razor index d1069ad..32e5b43 100644 --- a/src/Connected.Components/Components/Menu/Menu.razor +++ b/src/Connected.Components/Components/Menu/Menu.razor @@ -33,7 +33,7 @@ } else { - + } @* The portal has to include the cascading values inside, because it's not able to teletransport the cascade *@ diff --git a/src/Connected.Components/Components/NumericField/NumericField.razor b/src/Connected.Components/Components/NumericField/NumericField.razor index e816af2..c2bdca0 100644 --- a/src/Connected.Components/Components/NumericField/NumericField.razor +++ b/src/Connected.Components/Components/NumericField/NumericField.razor @@ -39,7 +39,7 @@ AdornmentColor="@AdornmentColor" IconSize="@IconSize" Error="@HasError" - Immediate="@(Immediate)" + ChangeTextImmediately="@(ChangeTextImmediately)" Margin="@Margin" MaxLength="@MaxLength" HideSpinButtons="@HideSpinButtons" diff --git a/src/Connected.Components/Components/Pagination/Pagination.razor b/src/Connected.Components/Components/Pagination/Pagination.razor index c63e0a4..253d99f 100644 --- a/src/Connected.Components/Components/Pagination/Pagination.razor +++ b/src/Connected.Components/Components/Pagination/Pagination.razor @@ -6,13 +6,13 @@ @if (ShowFirstButton) {
  • - +
  • } @if (ShowPreviousButton) {
  • - +
  • } @foreach (var state in GeneratePagination()) @@ -32,20 +32,20 @@ } else {
  • - +
  • } } @if (ShowNextButton) {
  • - +
  • } @if (ShowLastButton) {
  • - +
  • } \ No newline at end of file diff --git a/src/Connected.Components/Components/Slider/Slider.razor b/src/Connected.Components/Components/Slider/Slider.razor index 6141a22..b85826c 100644 --- a/src/Connected.Components/Components/Slider/Slider.razor +++ b/src/Connected.Components/Components/Slider/Slider.razor @@ -39,7 +39,7 @@ } + @bind-value="@Text" @bind-value:event="@((ChangeImmediately == true ? "oninput" : "onchange"))" /> @if (ValueLabel) {
    diff --git a/src/Connected.Components/Components/Slider/Slider.razor.cs b/src/Connected.Components/Components/Slider/Slider.razor.cs index c409c82..a1d4355 100644 --- a/src/Connected.Components/Components/Slider/Slider.razor.cs +++ b/src/Connected.Components/Components/Slider/Slider.razor.cs @@ -117,7 +117,7 @@ public partial class Slider : UIComponent ///
    [Parameter] [Category(CategoryTypes.Slider.Behavior)] - public bool Immediate { get; set; } = true; + public bool ChangeImmediately { get; set; } = true; /// /// If true, displays the slider vertical. diff --git a/src/Connected.Components/Components/Snackbar/SnackbarElement.razor b/src/Connected.Components/Components/Snackbar/SnackbarElement.razor index 4f9b6af..6e16ba2 100644 --- a/src/Connected.Components/Components/Snackbar/SnackbarElement.razor +++ b/src/Connected.Components/Components/Snackbar/SnackbarElement.razor @@ -23,12 +23,12 @@ @if (ShowActionButton) { - + } @if (ShowCloseIcon) { - + } } diff --git a/src/Connected.Components/Components/Table/TableGroupRow.razor b/src/Connected.Components/Components/Table/TableGroupRow.razor index 075d830..1ac2ecc 100644 --- a/src/Connected.Components/Components/Table/TableGroupRow.razor +++ b/src/Connected.Components/Components/Table/TableGroupRow.razor @@ -13,7 +13,7 @@
    @if (GroupDefinition.Expandable) { - + } else { diff --git a/src/Connected.Components/Components/Table/TablePager.razor b/src/Connected.Components/Components/Table/TablePager.razor index 93f35cc..d3a1b33 100644 --- a/src/Connected.Components/Components/Table/TablePager.razor +++ b/src/Connected.Components/Components/Table/TablePager.razor @@ -34,10 +34,10 @@ @if (!HidePagination) {
    - - - - + + + +
    } @if (HorizontalAlignment == HorizontalAlignment.Start || diff --git a/src/Connected.Components/Components/Table/Tr.razor b/src/Connected.Components/Components/Table/Tr.razor index 29f0371..2cab18d 100644 --- a/src/Connected.Components/Components/Table/Tr.razor +++ b/src/Connected.Components/Components/Table/Tr.razor @@ -15,19 +15,19 @@ } else { - + } } else if (object.ReferenceEquals(Context?.Table._editingItem, Item) && (!Context?.Table.ReadOnly ?? false) && Context?.Table.ApplyButtonPosition.DisplayApplyButtonAtStart() == true) {
    - + @if (Context.Table.CanCancelEdit) { - + }
    @@ -58,19 +58,19 @@ } else { - + } } else if (object.ReferenceEquals(Context?.Table._editingItem, Item) && (!Context?.Table.ReadOnly ?? false) && Context?.Table.ApplyButtonPosition.DisplayApplyButtonAtEnd() == true) {
    - + @if (Context.Table.CanCancelEdit) { - + }
    diff --git a/src/Connected.Components/Components/Tabs/DynamicTabs.razor b/src/Connected.Components/Components/Tabs/DynamicTabs.razor index f1aaa84..d049aa3 100644 --- a/src/Connected.Components/Components/Tabs/DynamicTabs.razor +++ b/src/Connected.Components/Components/Tabs/DynamicTabs.razor @@ -15,12 +15,12 @@ if (string.IsNullOrEmpty(AddIconToolTip) == false) { - + } else { - + } } ; @@ -30,12 +30,12 @@ if (string.IsNullOrEmpty(CloseIconToolTip) == false) { - + } else { - + } } ; diff --git a/src/Connected.Components/Components/Tabs/Tabs.razor b/src/Connected.Components/Components/Tabs/Tabs.razor index 34764b3..00da729 100644 --- a/src/Connected.Components/Components/Tabs/Tabs.razor +++ b/src/Connected.Components/Components/Tabs/Tabs.razor @@ -14,7 +14,7 @@ @if (_showScrollButtons) {
    - +
    }
    @@ -52,7 +52,7 @@ @if (_showScrollButtons) {
    - +
    } @if (HeaderPosition == TabHeaderPosition.After && Header != null) diff --git a/src/Connected.Components/Components/TextField/TextField.razor b/src/Connected.Components/Components/TextField/TextField.razor index 3479358..121dfef 100644 --- a/src/Connected.Components/Components/TextField/TextField.razor +++ b/src/Connected.Components/Components/TextField/TextField.razor @@ -25,7 +25,7 @@ @ref="InputReference" @attributes="CustomAttributes" InputType="@InputType" - Lines="@Lines" + NumberOfLines="@NumberOfLines" Variant="@Variant" TextUpdateSuppression="@TextUpdateSuppression" Value="@Text" @@ -44,7 +44,7 @@ OnAdornmentClick="@OnAdornmentClick" Error="@HasError" ErrorId="@ErrorId" - Immediate="@Immediate" + ChangeTextImmediately="@ChangeTextImmediately" Margin="@Margin" OnBlur="@OnBlurred" OnKeyDown="@InvokeKeyDown" @@ -65,7 +65,7 @@ @attributes="CustomAttributes" Mask="@_mask" InputType="@InputType" - Lines="@Lines" + NumberOfLines="@NumberOfLines" Variant="@Variant" TextUpdateSuppression="@TextUpdateSuppression" Value="@Text" @@ -82,7 +82,7 @@ IconSize="@IconSize" OnAdornmentClick="@OnAdornmentClick" Error="@HasError" - Immediate="@Immediate" + ChangeTextImmediately="@ChangeTextImmediately" Margin="@Margin" OnBlur="@OnBlurred" Clearable="@Clearable" diff --git a/src/Connected.Components/Components/TreeView/TreeViewItemToggleButton.razor b/src/Connected.Components/Components/TreeView/TreeViewItemToggleButton.razor index 8930d69..a62f0f6 100644 --- a/src/Connected.Components/Components/TreeView/TreeViewItemToggleButton.razor +++ b/src/Connected.Components/Components/TreeView/TreeViewItemToggleButton.razor @@ -5,7 +5,7 @@
    @if (Visible) { - + }
    diff --git a/src/Connected.Components/Utilities/Helper.cs b/src/Connected.Components/Utilities/Helper.cs new file mode 100644 index 0000000..43354f4 --- /dev/null +++ b/src/Connected.Components/Utilities/Helper.cs @@ -0,0 +1,23 @@ +namespace Connected.Utilities; +public static class Helper +{ + public static 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; + } + } +}