Prograss - Input field

features/refactor
stm 2 years ago
parent c5e97f9600
commit 3ea88592ce

@ -20,7 +20,7 @@
@if (CloseGlyphVisible) @if (CloseGlyphVisible)
{ {
<div class="alert-close"> <div class="alert-close">
<GlyphButton ClassList="size-small" Glyph="@CloseGlyph" Clicked="OnCloseGlyphClick" /> <IconButton ClassList="size-small" Icon="@CloseGlyph" Clicked="OnCloseGlyphClick" />
</div> </div>
} }
</div> </div>

@ -19,7 +19,7 @@
TextChanged="OnTextChanged" OnBlur="OnInputBlurred" TextChanged="OnTextChanged" OnBlur="OnInputBlurred"
OnKeyDown="@this.OnInputKeyDown" OnKeyDown="@this.OnInputKeyDown"
OnKeyUp="@this.OnInputKeyUp" autocomplete=@("disabled-"+Guid.NewGuid()) KeyUpPreventDefault="KeyUpPreventDefault" OnKeyUp="@this.OnInputKeyUp" autocomplete=@("disabled-"+Guid.NewGuid()) KeyUpPreventDefault="KeyUpPreventDefault"
Placeholder="@Placeholder" Immediate="true" Placeholder="@Placeholder" ChangeTextImmediately="true"
InputMode="@InputMode" Pattern="@Pattern" InputMode="@InputMode" Pattern="@Pattern"
T="string" /> T="string" />

@ -2,20 +2,20 @@
@inherits ButtonBase @inherits ButtonBase
@using Connected.Extensions; @using Connected.Components;
<Element disabled="@Disabled" <Element disabled="@Disabled"
title="@GlyphTitle" title="@IconTitle"
type="@ButtonType.ToDescription()" type="@ButtonType.ToString()"
ClassList="@CompiledClassList.ToString()" ClassList="@CompiledClassList.ToString()"
HtmlTag="@HtmlTag" HtmlTag="@HtmlTag"
PreventOnClickPropagation="PreventOnClickPropagation" PreventOnClickPropagation="PreventOnClickPropagation"
@attributes="CustomAttributes" @attributes="CustomAttributes"
@onclick="OnClick"> @onclick="OnClick">
@if (!String.IsNullOrEmpty(Glyph)) @if (!String.IsNullOrEmpty(Icon))
{ {
<span name="glyph-container" class="glyph-button-label"> <span name="glyph-container" class="glyph-button-label">
<Icon Glyph="@Glyph" /> <Icon Glyph="@Icon" />
</span> </span>
} }
else else

@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Components;
namespace Connected.Components; namespace Connected.Components;
public partial class GlyphButton : ButtonBase public partial class IconButton : ButtonBase
{ {
/// <summary> /// <summary>
/// Contains the default container classlist and the user defined classes. /// Contains the default container classlist and the user defined classes.
@ -28,16 +28,16 @@ public partial class GlyphButton : ButtonBase
#region Content placeholders #region Content placeholders
/// <summary> /// <summary>
/// The Glyph that will be used in the component. /// The Icon that will be used in the component.
/// </summary> /// </summary>
[Parameter] [Parameter]
public string? Glyph { get; set; } public string? Icon { get; set; }
/// <summary> /// <summary>
/// GlyphTitle of the icon used for accessibility. /// GlyphTitle of the icon used for accessibility.
/// </summary> /// </summary>
[Parameter] [Parameter]
public string? GlyphTitle { get; set; } public string? IconTitle { get; set; }
#endregion #endregion
#region Styling properties #region Styling properties

@ -2,12 +2,12 @@
@inherits UIComponent @inherits UIComponent
<GlyphButton aria-pressed="@Toggled.ToString()" <IconButton aria-pressed="@Toggled.ToString()"
ClassList="@ClassList" ClassList="@ClassList"
Clicked="Toggle" Clicked="Toggle"
Disabled="Disabled" Disabled="Disabled"
Glyph="@(Toggled ? ToggledGlyph : Glyph)" Icon="@(Toggled ? ToggledGlyph : Glyph)"
GlyphTitle="@(Toggled && ToggledGlyphTitle != null ? ToggledGlyphTitle : GlyphTitle)" IconTitle="@(Toggled && ToggledGlyphTitle != null ? ToggledGlyphTitle : GlyphTitle)"
Variant="Variant" Variant="Variant"
@attributes="CustomAttributes" @attributes="CustomAttributes"
/> />

@ -2,7 +2,7 @@
namespace Connected.Components; namespace Connected.Components;
public partial class ToggleGlyphButton : UIComponent public partial class ToggleIconButton : UIComponent
{ {
#region EventCallbacks #region EventCallbacks
/// <summary> /// <summary>

@ -31,7 +31,7 @@
{ {
@if (PreviousButtonTemplate == null) @if (PreviousButtonTemplate == null)
{ {
<IconButton tabindex="1" aria-label="Go to previous" Class="@NavigationButtonsClassName" Style="z-index:3;opacity:0.75" Icon="@PreviousIcon" OnClick="Previous" Color="ThemeColor.Inherit" /> <IconButton tabindex="1" aria-label="Go to previous" Class="@NavigationButtonsClassName" Style="z-index:3;opacity:0.75" Icon="@PreviousIcon" Clicked="Previous" Color="ThemeColor.Inherit" />
} }
else else
{ {
@ -51,7 +51,7 @@
int current = i; int current = i;
if (BulletTemplate == null) if (BulletTemplate == null)
{ {
<IconButton tabindex="@(i+3)" aria-label="@(i+1)" Class="@BulletsButtonsClassName" Style="z-index:3;opacity:0.75" Icon="@(current == SelectedIndex ? CheckedIcon : UncheckedIcon)" OnClick="(() => MoveTo(current))" Color="ThemeColor.Inherit" /> <IconButton tabindex="@(i+3)" aria-label="@(i+1)" Class="@BulletsButtonsClassName" Style="z-index:3;opacity:0.75" Icon="@(current == SelectedIndex ? CheckedIcon : UncheckedIcon)" Clicked="(() => MoveTo(current))" Color="ThemeColor.Inherit" />
} }
else else
{ {
@ -69,7 +69,7 @@
{ {
@if (NextButtonTemplate == null) @if (NextButtonTemplate == null)
{ {
<IconButton tabindex="2" aria-label="Go to next" Class="@NavigationButtonsClassName" Style="z-index:3;opacity:0.75" Icon="@NextIcon" OnClick="Next" Color="ThemeColor.Inherit" /> <IconButton tabindex="2" aria-label="Go to next" Class="@NavigationButtonsClassName" Style="z-index:3;opacity:0.75" Icon="@NextIcon" Clicked="Next" Color="ThemeColor.Inherit" />
} }
else else
{ {

@ -27,7 +27,7 @@
} }
@if (OnClose.HasDelegate || ChipSet?.AllClosable==true) @if (OnClose.HasDelegate || ChipSet?.AllClosable==true)
{ {
<IconButton Class="chip-close-button" Icon="@(String.IsNullOrEmpty(CloseIcon) ? $"{Icons.Material.Filled.Cancel}" : $"{CloseIcon}")" OnClick="OnCloseHandler" Size="Size.Small"/> <IconButton Class="chip-close-button" Icon="@(String.IsNullOrEmpty(CloseIcon) ? $"{Icons.Material.Filled.Cancel}" : $"{CloseIcon}")" Clicked="OnCloseHandler" Size="Size.Small"/>
} }
</span> </span>
</div> </div>

@ -12,12 +12,12 @@
<PickerToolbar DisableToolbar="@DisableToolbar" Class="picker-color-toolbar"> <PickerToolbar DisableToolbar="@DisableToolbar" Class="picker-color-toolbar">
@if (PickerVariant != PickerVariant.Static) @if (PickerVariant != PickerVariant.Static)
{ {
<IconButton Class="pa-1 mud-close-picker-button" Size="Size.Small" Color="ThemeColor.Inherit" Icon="@CloseIcon" OnClick="@GetEventCallback()" /> <IconButton Class="pa-1 mud-close-picker-button" Size="Size.Small" Color="ThemeColor.Inherit" Icon="@CloseIcon" Clicked="@GetEventCallback()" />
} }
<Spacer /> <Spacer />
<IconButton Class="pa-1" Size="Size.Small" Color="GetButtonColor(ColorPickerView.Spectrum)" Icon="@SpectrumIcon" OnClick="(() => ChangeView(ColorPickerView.Spectrum))" /> <IconButton Class="pa-1" Size="Size.Small" Color="GetButtonColor(ColorPickerView.Spectrum)" Icon="@SpectrumIcon" Clicked="(() => ChangeView(ColorPickerView.Spectrum))" />
<IconButton Class="pa-1 mx-1" Size="Size.Small" Color="GetButtonColor(ColorPickerView.Grid)" Icon="@GridIcon" OnClick="(() => ChangeView(ColorPickerView.Grid))" /> <IconButton Class="pa-1 mx-1" Size="Size.Small" Color="GetButtonColor(ColorPickerView.Grid)" Icon="@GridIcon" Clicked="(() => ChangeView(ColorPickerView.Grid))" />
<IconButton Class="pa-1" Size="Size.Small" Color="GetButtonColor(ColorPickerView.Palette)" Icon="@PaletteIcon" OnClick="(() => ChangeView(ColorPickerView.Palette))" /> <IconButton Class="pa-1" Size="Size.Small" Color="GetButtonColor(ColorPickerView.Palette)" Icon="@PaletteIcon" Clicked="(() => ChangeView(ColorPickerView.Palette))" />
</PickerToolbar> </PickerToolbar>
<PickerContent Class="picker-color-content"> <PickerContent Class="picker-color-content">
@if (!DisableColorField) @if (!DisableColorField)
@ -126,7 +126,7 @@
@if (!DisableModeSwitch) @if (!DisableModeSwitch)
{ {
<div class="picker-control-switch"> <div class="picker-control-switch">
<IconButton OnClick="ChangeMode" Icon="@ImportExportIcon" Class="pa-1 me-n1"></IconButton> <IconButton Clicked="ChangeMode" Icon="@ImportExportIcon" Class="pa-1 me-n1"></IconButton>
</div> </div>
} }
</div> </div>

@ -129,7 +129,7 @@
<IconButton <IconButton
Class="table-row-expander" Class="table-row-expander"
Icon="@(g.IsExpanded ? Icons.Material.Filled.ExpandMore : Icons.Material.Filled.ChevronRight)" Icon="@(g.IsExpanded ? Icons.Material.Filled.ExpandMore : Icons.Material.Filled.ChevronRight)"
OnClick="@(() => ToggleGroupExpansion(g))" /> Clicked="@(() => ToggleGroupExpansion(g))" />
@if (GroupedColumn.GroupTemplate == null) @if (GroupedColumn.GroupTemplate == null)
{ {
@ -377,7 +377,7 @@
@if (column == null) @if (column == null)
{ {
<Item xs="1" Class="d-flex"> <Item xs="1" Class="d-flex">
<IconButton Class="remove-filter-button" Icon="@Icons.Material.Filled.Close" OnClick="@filter.RemoveFilter" Size="@Size.Small" Style="align-self:flex-end"></IconButton> <IconButton Class="remove-filter-button" Icon="@Icons.Material.Filled.Close" Clicked="@filter.RemoveFilter" Size="@Size.Small" Style="align-self:flex-end"></IconButton>
</Item> </Item>
<Item xs="4"> <Item xs="4">
<Select T="string" Value="@f.Field" ValueChanged="@filter.FieldChanged" FullWidth="true" Label="Column" Dense="true" Margin="@Margin.Dense" <Select T="string" Value="@f.Field" ValueChanged="@filter.FieldChanged" FullWidth="true" Label="Column" Dense="true" Margin="@Margin.Dense"
@ -401,12 +401,12 @@
@if (filter.dataType == typeof(string) && !(f.Operator ?? "").EndsWith("empty")) @if (filter.dataType == typeof(string) && !(f.Operator ?? "").EndsWith("empty"))
{ {
<TextField T="string" Value="@filter._valueString" ValueChanged="@filter.StringValueChanged" FullWidth="true" Label="Value" Placeholder="Filter value" Margin="@Margin.Dense" <TextField T="string" Value="@filter._valueString" ValueChanged="@filter.StringValueChanged" FullWidth="true" Label="Value" Placeholder="Filter value" Margin="@Margin.Dense"
Immediate="true" Class="filter-input" /> ChangeTextImmediately="true" Class="filter-input" />
} }
else if (filter.isNumber && !(f.Operator ?? "").EndsWith("empty")) else if (filter.isNumber && !(f.Operator ?? "").EndsWith("empty"))
{ {
<NumericField T="double?" Value="@filter._valueNumber" ValueChanged="@filter.NumberValueChanged" FullWidth="true" Label="Value" Placeholder="Filter value" Margin="@Margin.Dense" <NumericField T="double?" Value="@filter._valueNumber" ValueChanged="@filter.NumberValueChanged" FullWidth="true" Label="Value" Placeholder="Filter value" Margin="@Margin.Dense"
Immediate="true" Class="filter-input" Culture="@filter.filterColumn?.Culture" /> ChangeTextImmediately="true" Class="filter-input" Culture="@filter.filterColumn?.Culture" />
} }
else if (filter.isEnum) else if (filter.isEnum)
{ {
@ -442,7 +442,7 @@
else if (filter.dataType == typeof(Guid)) else if (filter.dataType == typeof(Guid))
{ {
<TextField T="string" Value="@filter._valueString" ValueChanged="@filter.StringValueChanged" FullWidth="true" Label="Value" Placeholder="Filter value" Margin="@Margin.Dense" <TextField T="string" Value="@filter._valueString" ValueChanged="@filter.StringValueChanged" FullWidth="true" Label="Value" Placeholder="Filter value" Margin="@Margin.Dense"
Immediate="true" Class="filter-input" /> ChangeTextImmediately="true" Class="filter-input" />
} }
</Item> </Item>
} }
@ -461,12 +461,12 @@
@if (filter.dataType == typeof(string) && !(f.Operator ?? "").EndsWith("empty")) @if (filter.dataType == typeof(string) && !(f.Operator ?? "").EndsWith("empty"))
{ {
<TextField T="string" Value="@filter._valueString" ValueChanged="@filter.StringValueChanged" FullWidth="true" Placeholder="Filter value" Margin="@Margin.Dense" <TextField T="string" Value="@filter._valueString" ValueChanged="@filter.StringValueChanged" FullWidth="true" Placeholder="Filter value" Margin="@Margin.Dense"
Immediate="true" Class="filter-input" /> ChangeTextImmediately="true" Class="filter-input" />
} }
else if (filter.isNumber && !(f.Operator ?? "").EndsWith("empty")) else if (filter.isNumber && !(f.Operator ?? "").EndsWith("empty"))
{ {
<NumericField T="double?" Value="@filter._valueNumber" ValueChanged="@filter.NumberValueChanged" FullWidth="true" Placeholder="Filter value" Margin="@Margin.Dense" <NumericField T="double?" Value="@filter._valueNumber" ValueChanged="@filter.NumberValueChanged" FullWidth="true" Placeholder="Filter value" Margin="@Margin.Dense"
Immediate="true" Class="filter-input" Culture="@filter.filterColumn?.Culture" /> ChangeTextImmediately="true" Class="filter-input" Culture="@filter.filterColumn?.Culture" />
} }
else if (filter.isEnum) else if (filter.isEnum)
{ {
@ -502,7 +502,7 @@
else if (filter.dataType == typeof(Guid)) else if (filter.dataType == typeof(Guid))
{ {
<TextField T="string" Value="@filter._valueString" ValueChanged="@filter.StringValueChanged" FullWidth="true" Label="Value" Placeholder="Filter value" Margin="@Margin.Dense" <TextField T="string" Value="@filter._valueString" ValueChanged="@filter.StringValueChanged" FullWidth="true" Label="Value" Placeholder="Filter value" Margin="@Margin.Dense"
Immediate="true" Class="filter-input" /> ChangeTextImmediately="true" Class="filter-input" />
} }
</Item> </Item>
} }

@ -20,10 +20,10 @@
@Info @Info
</TextContent> </TextContent>
<div class="table-pagination-actions"> <div class="table-pagination-actions">
<IconButton Class="flip-x-rtl" Icon="@Icons.Material.Filled.FirstPage" Disabled="@BackButtonsDisabled" @onclick="@(() => DataGrid.NavigateTo(Page.First))"/> <IconButton Class="flip-x-rtl" Icon="@Icons.Material.Filled.FirstPage" Disabled="@BackButtonsDisabled" Clicked="@(() => DataGrid.NavigateTo(Page.First))" />
<IconButton Class="flip-x-rtl" Icon="@Icons.Material.Filled.NavigateBefore" Disabled="@BackButtonsDisabled" @onclick="@(() => DataGrid.NavigateTo(Page.Previous))"/> <IconButton Class="flip-x-rtl" Icon="@Icons.Material.Filled.NavigateBefore" Disabled="@BackButtonsDisabled" Clicked="@(() => DataGrid.NavigateTo(Page.Previous))" />
<IconButton Class="flip-x-rtl" Icon="@Icons.Material.Filled.NavigateNext" Disabled="@ForwardButtonsDisabled" @onclick="@(() => DataGrid.NavigateTo(Page.Next))"/> <IconButton Class="flip-x-rtl" Icon="@Icons.Material.Filled.NavigateNext" Disabled="@ForwardButtonsDisabled" Clicked="@(() => DataGrid.NavigateTo(Page.Next))" />
<IconButton Class="flip-x-rtl" Icon="@Icons.Material.Filled.LastPage" Disabled="@ForwardButtonsDisabled" @onclick="@(() => DataGrid.NavigateTo(Page.Last))"/> <IconButton Class="flip-x-rtl" Icon="@Icons.Material.Filled.LastPage" Disabled="@ForwardButtonsDisabled" Clicked="@(() => DataGrid.NavigateTo(Page.Last))" />
</div> </div>
</ToolBar> </ToolBar>

@ -14,11 +14,11 @@
<Stack Row="true"> <Stack Row="true">
@if (dataType == typeof(string) && !(_operator ?? "").EndsWith("empty")) @if (dataType == typeof(string) && !(_operator ?? "").EndsWith("empty"))
{ {
<TextField T="string" Value="@_valueString" ValueChanged="@StringValueChanged" FullWidth="true" Placeholder="Filter value" Margin="@Margin.Dense" Immediate="true" /> <TextField T="string" Value="@_valueString" ValueChanged="@StringValueChanged" FullWidth="true" Placeholder="Filter value" Margin="@Margin.Dense" ChangeTextImmediately="true" />
} }
else if (isNumber && !(_operator ?? "").EndsWith("empty")) else if (isNumber && !(_operator ?? "").EndsWith("empty"))
{ {
<NumericField T="double?" Culture="@Column.Culture" Value="@_valueNumber" ValueChanged="@NumberValueChanged" FullWidth="true" Placeholder="Filter value" Margin="@Margin.Dense" Immediate="true"></NumericField> <NumericField T="double?" Culture="@Column.Culture" Value="@_valueNumber" ValueChanged="@NumberValueChanged" FullWidth="true" Placeholder="Filter value" Margin="@Margin.Dense" ChangeTextImmediately="true"></NumericField>
} }
else if (isEnum) else if (isEnum)
{ {
@ -58,7 +58,7 @@
} }
} }
</Menu> </Menu>
<GlyphButton Class="align-self-center" Icon="@Icons.Material.Filled.FilterAltOff" Size="@Size.Small" Clicked="@ClearFilter"></GlyphButton> <IconButton Class="align-self-center" Icon="@Icons.Material.Filled.FilterAltOff" Size="@Size.Small" Clicked="@ClearFilter"></IconButton>
</Stack> </Stack>
} }
} }

@ -41,11 +41,11 @@ else if (Column != null && !Column.Hidden)
{ {
if (_initialDirection == SortDirection.None) if (_initialDirection == SortDirection.None)
{ {
<IconButton Icon="@Column.SortIcon" Class="@sortIconClass" Size="@Size.Small" OnClick="@SortChangedAsync"></IconButton> <IconButton Icon="@Column.SortIcon" Class="@sortIconClass" Size="@Size.Small" Clicked="@SortChangedAsync"></IconButton>
} }
else else
{ {
<IconButton Icon="@Column.SortIcon" Class="@sortIconClass" Size="@Size.Small" OnClick="@SortChangedAsync"></IconButton> <IconButton Icon="@Column.SortIcon" Class="@sortIconClass" Size="@Size.Small" Clicked="@SortChangedAsync"></IconButton>
if(DataGrid.SortMode == SortMode.Multiple) if(DataGrid.SortMode == SortMode.Multiple)
{ {
<span class="sort-index mud-text-disabled">@(Column.SortIndex + 1)</span> <span class="sort-index mud-text-disabled">@(Column.SortIndex + 1)</span>
@ -57,11 +57,11 @@ else if (Column != null && !Column.Hidden)
{ {
if (hasFilter) if (hasFilter)
{ {
<IconButton Class="filter-button filtered" Icon="@Icons.Material.Filled.FilterAlt" Size="@Size.Small" OnClick="@OpenFilters"></IconButton> <IconButton Class="filter-button filtered" Icon="@Icons.Material.Filled.FilterAlt" Size="@Size.Small" Clicked="@OpenFilters"></IconButton>
} }
else if (showFilterIcon) else if (showFilterIcon)
{ {
<IconButton Class="filter-button" Icon="@Icons.Material.Outlined.FilterAlt" Size="@Size.Small" OnClick="@AddFilter"></IconButton> <IconButton Class="filter-button" Icon="@Icons.Material.Outlined.FilterAlt" Size="@Size.Small" Clicked="@AddFilter"></IconButton>
} }
} }

@ -47,11 +47,11 @@
<div class="picker-calendar-header-switch"> <div class="picker-calendar-header-switch">
@if (!FixYear.HasValue) @if (!FixYear.HasValue)
{ {
<IconButton aria-label="@prevLabel" Icon="@PreviousIcon" OnClick="OnPreviousYearClick" Class="flip-x-rtl" /> <IconButton aria-label="@prevLabel" Icon="@PreviousIcon" Clicked="OnPreviousYearClick" Class="flip-x-rtl" />
<button type="button" class="picker-slide-transition mud-picker-calendar-header-transition" @onclick="OnYearClick" @onclick:stopPropagation="true"> <button type="button" class="picker-slide-transition mud-picker-calendar-header-transition" @onclick="OnYearClick" @onclick:stopPropagation="true">
<TextContent Typo="Typo.body1" Align="Align.Center">@calendarYear</TextContent> <TextContent Typo="Typo.body1" Align="Align.Center">@calendarYear</TextContent>
</button> </button>
<IconButton aria-label="@nextLabel" Icon="@NextIcon" OnClick="OnNextYearClick" Class="flip-x-rtl" /> <IconButton aria-label="@nextLabel" Icon="@NextIcon" Clicked="OnNextYearClick" Class="flip-x-rtl" />
} }
else else
{ {
@ -77,11 +77,11 @@
<div class="picker-calendar-header-switch"> <div class="picker-calendar-header-switch">
@if (!FixMonth.HasValue) @if (!FixMonth.HasValue)
{ {
<IconButton aria-label="@prevLabel" Class="picker-nav-button-prev mud-flip-x-rtl" Icon="@PreviousIcon" OnClick="OnPreviousMonthClick" /> <IconButton aria-label="@prevLabel" Class="picker-nav-button-prev mud-flip-x-rtl" Icon="@PreviousIcon" Clicked="OnPreviousMonthClick" />
<button type="button" class="picker-slide-transition mud-picker-calendar-header-transition mud-button-month" @onclick="(() => OnMonthClicked(tempMonth))" @onclick:stopPropagation="true"> <button type="button" class="picker-slide-transition mud-picker-calendar-header-transition mud-button-month" @onclick="(() => OnMonthClicked(tempMonth))" @onclick:stopPropagation="true">
<TextContent Typo="Typo.body1" Align="Align.Center">@GetMonthName(tempMonth)</TextContent> <TextContent Typo="Typo.body1" Align="Align.Center">@GetMonthName(tempMonth)</TextContent>
</button> </button>
<IconButton aria-label="@nextLabel" Class="picker-nav-button-next mud-flip-x-rtl" Icon="@NextIcon" OnClick="OnNextMonthClick" /> <IconButton aria-label="@nextLabel" Class="picker-nav-button-next mud-flip-x-rtl" Icon="@NextIcon" Clicked="OnNextMonthClick" />
} }
else else
{ {

@ -17,7 +17,7 @@
} }
@if (CloseButton) @if (CloseButton)
{ {
<IconButton aria-label="close" Icon="@CloseIcon" @onclick="Cancel"/> <IconButton aria-label="close" Icon="@CloseIcon" Clicked="Cancel" />
} }
</div> </div>
} }

@ -60,7 +60,7 @@ public partial class Form : UIComponent, IDisposable, IForm
/// <summary> /// <summary>
/// Validation debounce delay in milliseconds. This can help improve rendering performance of forms with real-time validation of inputs /// Validation debounce delay in milliseconds. This can help improve rendering performance of forms with real-time validation of inputs
/// i.e. when textfields have Immediate="true". /// i.e. when textfields have ChangeTextImmediately="true".
/// </summary> /// </summary>
[Parameter] [Parameter]
[Category(CategoryTypes.Form.Behavior)] [Category(CategoryTypes.Form.Behavior)]

@ -72,10 +72,10 @@ public abstract class DebouncedInput<T> : InputBase<T>
protected override void OnParametersSet() protected override void OnParametersSet()
{ {
base.OnParametersSet(); base.OnParametersSet();
// if input is to be debounced, makes sense to bind the change of the text to oninput // if input is to be debounced, makes sense to bind the change of the text to oninput
// so we set Immediate to true // so we set ChangeTextImmediately to true
if (DebounceInterval > 0) if (DebounceInterval > 0)
Immediate = true; ChangeTextImmediately = true;
} }
private void SetTimer() private void SetTimer()

@ -2,162 +2,147 @@
@typeparam T @typeparam T
@inherits InputBase<T> @inherits InputBase<T>
<InputControl Label="@Label" <div class="@CompiledWrapperClass.Build()">
Variant="@Variant"
HelperText="@HelperText"
HelperTextOnFocus="@HelperTextOnFocus"
CounterText="@GetCounterText()"
FullWidth="@FullWidth"
Class="@CompiledClassList.Build()"
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="@CompiledAdornmentClass.Build()"
Icon="@AdornmentIcon" Icon="@AdornmentIcon"
Color="@AdornmentColor" Color="@AdornmentColor"
Size="@IconSize" Size="@IconSize"
Text="@AdornmentText" Text="@AdornmentText"
Edge="@Edge.Start" Edge="@Edge.Start"
AdornmentClick="@OnAdornmentClick" AdornmentClick="@OnAdornmentClick"
AriaLabel="@AdornmentAriaLabel" AriaLabel="@AdornmentAriaLabel"
/> />
} }
<InputContent>
@if (Lines > 1)
{
<textarea class="@InputClassname"
@ref="ElementReference"
rows="@Lines"
@attributes="CustomAttributes"
type="@InputTypeString"
placeholder="@Placeholder"
disabled=@Disabled
readonly="@ReadOnly"
inputmode="@InputMode.ToString()"
@oninput="OnInput"
@onchange="OnChange"
@onblur="@OnBlurred"
@onkeydown="@InvokeKeyDown"
@onkeypress="@InvokeKeyPress"
@onkeyup="@InvokeKeyUp"
@onpaste="@OnPaste"
value="@_internalText"
maxlength="@MaxLength"
@onkeydown:preventDefault="@KeyDownPreventDefault"
@onkeypress:preventDefault="@KeyPressPreventDefault"
@onkeyup:preventDefault="@KeyUpPreventDefault"
@onmousewheel="@OnMouseWheel"
@onwheel="@OnMouseWheel"
aria-invalid="@HasError.ToString().ToLower()"
aria-describedby="@ErrorId">
@Text
</textarea>
@*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
{
<input class="@InputClassname"
@ref="ElementReference"
@attributes="CustomAttributes"
type="@InputTypeString"
value="@_internalText"
@oninput="OnInput"
@onchange="OnChange"
placeholder="@Placeholder"
disabled=@Disabled
readonly="@ReadOnly"
@onblur="@OnBlurred"
inputmode="@InputMode.ToString()"
pattern="@Pattern"
@onkeydown="@InvokeKeyDown"
@onkeypress="@InvokeKeyPress"
@onkeyup="@InvokeKeyUp"
maxlength="@MaxLength"
@onkeydown:preventDefault="KeyDownPreventDefault"
@onkeypress:preventDefault="@KeyPressPreventDefault"
@onkeyup:preventDefault="@KeyUpPreventDefault"
@onmousewheel="@OnMouseWheel"
@onwheel="@OnMouseWheel"
aria-invalid="@HasError.ToString().ToLower()"
aria-describedby="@ErrorId"
/>
@*Note: double mouse wheel handlers needed for Firefox because it doesn't know onmousewheel*@
@if (Disabled) { @if (NumberOfLines > 1)
@*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 <textarea class="@CompiledInputClass.Build()"
*@ @ref="ElementReference"
<div class="@InputClassname" rows="@NumberOfLines"
style="@("display:"+(InputType == InputType.Hidden && ChildContent != null ? "inline" : "none"))" style="@Style"
@onblur="@OnBlurred" @ref="@_elementReference1" @attributes="@Attributes"
> type="@InputTypeString"
@ChildContent placeholder="@Placeholder"
</div> disabled=@Disabled
} readonly="@ReadOnly"
else inputmode="@InputMode.ToString()"
{ @oninput="OnInput"
@*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.*@ @onchange="OnChange"
<div class="@InputClassname" @onblur="@OnBlurred"
style="@("display:"+(InputType == InputType.Hidden && ChildContent != null ? "inline" : "none"))" @onkeydown="@InvokeKeyDown"
tabindex="@(InputType == InputType.Hidden && ChildContent != null ? 0 : -1)" @onkeypress="@InvokeKeyPress"
@onblur="@OnBlurred" @ref="@_elementReference1" @onkeyup="@InvokeKeyUp"
> @onpaste="@OnPaste"
@ChildContent value="@_internalText"
</div> maxlength="@MaxLength"
} @onkeydown:preventDefault="@KeyDownPreventDefault"
@onkeypress:preventDefault="@KeyPressPreventDefault"
@onkeyup:preventDefault="@KeyUpPreventDefault"
@onmousewheel="@OnMouseWheel"
@onwheel="@OnMouseWheel"
aria-invalid="@HasError.ToString().ToLower()"
aria-describedby="@ErrorId"
>
@Text
</textarea>
@*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
{
<input class="@CompiledInputClass.Build()"
style="@Style"
@ref="ElementReference"
@attributes="@Attributes"
step="@Step"
type="@InputTypeString"
value="@_internalText"
@oninput="OnInput"
@onchange="OnChange"
placeholder="@Placeholder"
disabled=@Disabled
readonly="@ReadOnly"
@onblur="@OnBlurred"
inputmode="@InputMode.ToString()"
pattern="@Pattern"
@onkeydown="@InvokeKeyDown"
@onkeypress="@InvokeKeyPress"
@onkeyup="@InvokeKeyUp"
maxlength="@MaxLength"
@onkeydown:preventDefault="KeyDownPreventDefault"
@onkeypress:preventDefault="@KeyPressPreventDefault"
@onkeyup:preventDefault="@KeyUpPreventDefault"
@onmousewheel="@OnMouseWheel"
@onwheel="@OnMouseWheel"
aria-invalid="@HasError.ToString().ToLower()"
aria-describedby="@ErrorId"
/>
@*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
*@
<div class="@CompiledInputClass.Build()"
style="@("display:"+(InputType == InputType.Hidden && ChildContent != null ? "inline" : "none"))"
@onblur="@OnBlurred" @ref="@_elementReference1"
>
@ChildContent
</div>
} }
else
@if (_showClearable && !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.*@
<div class="@CompiledInputClass.Build()"
style="@("display:"+(InputType == InputType.Hidden && ChildContent != null ? "inline" : "none"))"
tabindex="@(InputType == InputType.Hidden && ChildContent != null ? 0 : -1)"
@onblur="@OnBlurred" @ref="@_elementReference1"
>
@ChildContent
</div>
} }
}
@if (_showClearable && !Disabled)
{
<IconButton ClassList="@CompiledClearButtonClassList.Build()"
Icon="@ClearIcon"
Clicked="@ClearButtonClickHandlerAsync"
tabindex="-1"
/>
}
@if (Adornment == Adornment.End)
@if (Adornment == Adornment.End) {
{ <InputAdornment Class="@CompiledAdornmentClass.Build()"
<InputAdornment Class="@AdornmentClassname"
Icon="@AdornmentIcon" Icon="@AdornmentIcon"
Color="@AdornmentColor" Color="@AdornmentColor"
Size="@IconSize" Size="@IconSize"
Text="@AdornmentText" Text="@AdornmentText"
Edge="@Edge.End" Edge="@Edge.End"
AdornmentClick="@OnAdornmentClick" AdornmentClick="@OnAdornmentClick"
AriaLabel="@AdornmentAriaLabel" AriaLabel="@AdornmentAriaLabel"
/> />
} }
@if (Variant == Variant.Outlined)
{
<div class="input-outlined-border"></div>
}
@if (!HideSpinButtons)
{
<div class="input-numeric-spin">
<Button Variant="Variant.Text" @onclick="OnIncrement" Disabled="@(Disabled || ReadOnly)" tabindex="-1">
<Icon Icon="@NumericUpIcon" Size="@GetButtonSize()" />
</Button>
<Button Variant="Variant.Text" @onclick="OnDecrement" Disabled="@(Disabled || ReadOnly)" tabindex="-1">
<Icon Icon="@NumericDownIcon" Size="@GetButtonSize()" />
</Button>
</div>
}
</InputContent>
</CascadingValue> @if (Variant == Variant.Outlined)
{
<div class="input-outlined-border"></div>
}
</InputControl> @if (!HideSpinButtons)
{
<div class="input-numeric-spin">
<Button Variant="Variant.Text" Clicked="OnIncrement" Disabled="@(Disabled || ReadOnly)" tabindex="-1">
<Icon Icon="@NumericUpIcon" Size="@GetButtonSize()" />
</Button>
<Button Variant="Variant.Text" Clicked="OnDecrement" Disabled="@(Disabled || ReadOnly)" tabindex="-1">
<Icon Icon="@NumericDownIcon" Size="@GetButtonSize()" />
</Button>
</div>
}
</div>

@ -9,39 +9,18 @@ namespace Connected.Components;
public partial class Input<T> : InputBase<T> public partial class Input<T> : InputBase<T>
{ {
/* #region Event Callbacks
* Debounce
*
*/
/// <summary> /// <summary>
/// The current character counter, displayed below the text field. /// Paste hook for descendants.
/// </summary> /// </summary>
[Parameter] public string CounterText { get; set; } #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
private System.Timers.Timer _timer;
private double _debounceInterval;
/// <summary> protected virtual async Task OnPaste(ClipboardEventArgs args)
/// Interval to be awaited in MILLISECONDS before changing the Text value #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
/// </summary>
[Parameter]
public double TextChangeDelay
{ {
get => _debounceInterval; // do nothing
set return;
{
if (NumericConverter<double>.AreEqual(_debounceInterval, value))
return;
_debounceInterval = value;
if (_debounceInterval == 0)
{
// not debounced, dispose timer if any
ClearTimer(suppressTick: false);
return;
}
SetTimer();
}
} }
/// <summary> /// <summary>
@ -81,126 +60,232 @@ public partial class Input<T> : InputBase<T>
return Task.CompletedTask; return Task.CompletedTask;
} }
protected override void OnParametersSet() private void OnTimerTick(object sender, ElapsedEventArgs e)
{ {
base.OnParametersSet(); InvokeAsync(OnTimerTickGuiThread).AndForget();
// 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() 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.Stop();
_timer.Elapsed += OnTimerTick; await UpdateValuePropertyAsync(false);
_timer.AutoReset = 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) /// <summary>
/// Invokes the callback when the Up arrow button is clicked when the input is set to <see cref="InputType.Number"/>.
/// Note: use the optimized control <see cref="NumericField{T}"/> if you need to deal with numbers.
/// </summary>
[Parameter] public EventCallback OnIncrement { get; set; }
/// <summary>
/// Invokes the callback when the Down arrow button is clicked when the input is set to <see cref="InputType.Number"/>.
/// Note: use the optimized control <see cref="NumericField{T}"/> if you need to deal with numbers.
/// </summary>
[Parameter] public EventCallback OnDecrement { get; set; }
/// <summary>
/// Button click event for clear button. Called after text and value has been cleared.
/// </summary>
[Parameter] public EventCallback<MouseEventArgs> OnClearButtonClick { get; set; }
/// <summary>
/// Mouse wheel event for input.
/// </summary>
[Parameter] public EventCallback<WheelEventArgs> 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); return ElementReference.BlurAsync();
await OnDebounceIntervalElapsed.InvokeAsync(Text);
} }
private void ClearTimer(bool suppressTick = false) public override ValueTask SelectAsync()
{ {
if (_timer == null) return ElementReference.SelectAsync();
return;
var wasEnabled = _timer.Enabled;
_timer.Stop();
_timer.Elapsed -= OnTimerTick;
_timer.Dispose();
_timer = null;
if (wasEnabled && !suppressTick)
OnTimerTickGuiThread().AndForget();
} }
/* public override ValueTask SelectRangeAsync(int pos1, int pos2)
* Debounce end {
*/ return ElementReference.SelectRangeAsync(pos1, pos2);
}
protected CssBuilder CompiledHelperContainerClassList private void UpdateClearable(object value)
{ {
get var showClearable = Clearable && ((value is string stringValue && !string.IsNullOrWhiteSpace(stringValue)) || (value is not string && value is not null));
{ if (_showClearable != showClearable)
return new CssBuilder("input-control-helper-container") _showClearable = showClearable;
.AddClass($"px-1", Variant == Variant.Filled)
.AddClass($"px-2", Variant == Variant.Outlined)
.AddClass($"px-1", Variant == Variant.Text)
.AddClass(CompiledClearButtonClassList.Build())
.AddClass(CompiledHelperClassList.Build());
}
} }
protected CssBuilder CompiledClearButtonClassList protected override async Task UpdateTextPropertyAsync(bool updateValue)
{ {
get await base.UpdateTextPropertyAsync(updateValue);
{ if (Clearable)
return new CssBuilder() UpdateClearable(Text);
.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) protected virtual async Task ClearButtonClickHandlerAsync(MouseEventArgs e)
.AddClass("icon-button-edge-margin-end", Adornment != Adornment.End && HideSpinButtons == true); {
} await SetTextAsync(string.Empty, updateValue: true);
await ElementReference.FocusAsync();
await OnClearButtonClick.InvokeAsync(e);
} }
/// <summary> /// <summary>
/// A space separated list of class names, added on top of the default helper container class list. /// Custom input Attributes
/// </summary> /// </summary>
[Parameter] [Parameter] public Dictionary<string, object>? Attributes { get; set; } = null;
public string? HelperContainerClassList { get; set; }
#endregion
#region Style properties
/// <summary>
/// Type of the input element. It should be a valid HTML5 input type.
/// </summary>
[Parameter] public InputType InputType { get; set; } = InputType.Text;
protected CssBuilder CompiledHelperClassList private string ClearIcon = Icons.Material.Filled.Clear;
private string NumericUpIcon = Icons.Material.Filled.KeyboardArrowUp;
private string NumericDownIcon = Icons.Material.Filled.KeyboardArrowDown;
/// <summary>
/// Hides the spin buttons"/>
/// </summary>
[Parameter] public bool HideSpinButtons { get; set; } = true;
/// <summary>
/// Show clear button.
/// </summary>
[Parameter] public bool Clearable { get; set; } = false;
#region Wrapper class
[Parameter]
public string WrapperClass { get; set; } = string.Empty;
protected CssBuilder CompiledWrapperClass
{ {
get get
{ {
return new CssBuilder("input-helper-text") return new CssBuilder("input")
.AddClass("input-helper-onfocus", HelperTextOnFocus) .AddClass($"input-{Variant.ToDescription()}")
.AddClass(HelperClassList); .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);
} }
} }
/// <summary>
/// A space separated list of class names, added on top of the default helper class list.
/// </summary>
[Parameter]
public string? HelperClassList { get; set; }
#endregion
/*protected string HelperContainer => #region Input field class
new CssBuilder("input-control-helper-container")
.AddClass($"px-1", Variant == Variant.Filled)
.AddClass($"px-2", Variant == Variant.Outlined)
.Build();
[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 => #region Adornment class
new CssBuilder("input-helper-text") [Parameter]
.AddClass("input-helper-onfocus", HelperTextOnFocus) public string AdornmentClass { get; set; } = string.Empty;
.Build();*/ 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(); get
if (string.IsNullOrEmpty(Text)) result = "0"; {
return result; 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, #region Helper container class
() => HasNativeHtmlPlaceholder() || !string.IsNullOrEmpty(Text) || Adornment == Adornment.Start || !string.IsNullOrWhiteSpace(Placeholder));
protected CssBuilder CompiledClassList /// <summary>
/// A space separated list of class names, added on top of the default helper container class list.
/// </summary>
[Parameter]
public string? HelperContainerClass { get; set; }
protected CssBuilder CompiledHelperContainerClassList
{ {
get get
{ {
@ -208,304 +293,149 @@ public partial class Input<T> : InputBase<T>
.AddClass($"px-1", Variant == Variant.Filled) .AddClass($"px-1", Variant == Variant.Filled)
.AddClass($"px-2", Variant == Variant.Outlined) .AddClass($"px-2", Variant == Variant.Outlined)
.AddClass($"px-1", Variant == Variant.Text) .AddClass($"px-1", Variant == Variant.Text)
.AddClass(CompiledClearButtonClassList.Build()) .AddClass(HelperContainerClass);
.AddClass(CompiledHelperClassList.Build());
} }
} }
protected string InputClassname => InputCssHelper.GetInputClassname(this); #endregion
protected string AdornmentClassname => InputCssHelper.GetAdornmentClassname(this); #region Error container class -- still needs implementation
#endregion
/// <summary> #region Counter container class -- still needs implementation
/// Type of the input element. It should be a valid HTML5 input type.
/// </summary>
[Parameter] public InputType InputType { get; set; } = InputType.Text;
internal override InputType GetInputType() => InputType; #endregion
protected string InputTypeString => InputType.ToDescription(); #endregion
/*
private bool IsDecimalNumber(string type)
#region Content placeholders
/// <summary>
/// The current character counter, displayed below the text field.
/// </summary>
[Parameter] public string CounterText { get; set; }
private System.Timers.Timer _timer;
private double _textChangeInterval;
/// <summary>
/// Interval to be awaited in MILLISECONDS before changing the Text value
/// </summary>
[Parameter]
public double TextChangeDelay
{ {
switch (type.ToLower()) get => _textChangeInterval;
set
{ {
case "double": if (NumericConverter<double>.AreEqual(_textChangeInterval, value))
case "float": return;
return true; _textChangeInterval = value;
default: if (_textChangeInterval == 0)
return false; {
// not debounced, dispose timer if any
ClearTimer(suppressTick: false);
return;
}
SetTimer();
} }
} }
private bool IsNumber(string s) private void SetTimer()
{ {
bool result = false; if (_timer == null)
try
{
double d;
result= double.TryParse(s, out d);
} catch
{ {
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 (_timer == null)
if (value is not null) return;
{ var wasEnabled = _timer.Enabled;
var expectedType = typeof(T).Name; _timer.Stop();
if (IsNumericType(expectedType)) _timer.Elapsed -= OnTimerTick;
{ _timer.Dispose();
if (IsNumber(value.ToString())) _timer = null;
{ if (wasEnabled && !suppressTick)
result = value.ToString(); OnTimerTickGuiThread().AndForget();
} }
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) /// <summary>
{ /// ChildContent of the MudInput will only be displayed if InputType.Hidden and if its not null.
if (!Immediate) /// </summary>
return Task.CompletedTask; [Parameter] public RenderFragment ChildContent { get; set; }
_isFocused = true;
return SetTextAsync(args?.Value as string);
private string TextCounter()
{
if (string.IsNullOrEmpty(Text)) return "0";
return Text.Length.ToString();
} }
protected async Task OnChange(ChangeEventArgs args) [Parameter]
{ public double Step { get; set; } = 1;
if (TextChangeDelay > 0 && _timer != null) 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(); // Text update suppression, only in BSS (not in WASM).
await UpdateValuePropertyAsync(false); // This is a fix for #1012
if (!_isFocused || _forceTextUpdate)
_internalText = Text;
} }
else else
{ {
_internalText = args?.Value as string; // in WASM (or in BSS with TextUpdateSuppression==false) we always update
await OnInternalInputChanged.InvokeAsync(args); _internalText = Text;
if (!Immediate)
{
await SetTextAsync(args?.Value as string);
}
} }
} if (Helper.IsNumericType(typeof(T).Name) && InputType != InputType.Number)
/// <summary>
/// Paste hook for descendants.
/// </summary>
#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;
}
/// <summary>
/// ChildContent of the MudInput will only be displayed if InputType.Hidden and if its not null.
/// </summary>
[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);
}
/// <summary>
/// Invokes the callback when the Up arrow button is clicked when the input is set to <see cref="InputType.Number"/>.
/// Note: use the optimized control <see cref="NumericField{T}"/> if you need to deal with numbers.
/// </summary>
[Parameter] public EventCallback OnIncrement { get; set; }
/// <summary>
/// Invokes the callback when the Down arrow button is clicked when the input is set to <see cref="InputType.Number"/>.
/// Note: use the optimized control <see cref="MudNumericField{T}"/> if you need to deal with numbers.
/// </summary>
[Parameter] public EventCallback OnDecrement { get; set; }
/// <summary>
/// Hides the spin buttons for <see cref="MudNumericField{T}"/>
/// </summary>
[Parameter] public bool HideSpinButtons { get; set; } = true;
/// <summary>
/// Show clear button.
/// </summary>
[Parameter] public bool Clearable { get; set; } = false;
/// <summary>
/// Button click event for clear button. Called after text and value has been cleared.
/// </summary>
[Parameter] public EventCallback<MouseEventArgs> OnClearButtonClick { get; set; }
/// <summary>
/// Mouse wheel event for input.
/// </summary>
[Parameter] public EventCallback<WheelEventArgs> OnMouseWheel { get; set; }
/// <summary>
/// Custom clear icon.
/// </summary>
[Parameter] public string ClearIcon { get; set; } = Icons.Material.Filled.Clear;
/// <summary>
/// Custom numeric up icon.
/// </summary>
[Parameter] public string NumericUpIcon { get; set; } = Icons.Material.Filled.KeyboardArrowUp;
/// <summary>
/// Custom numeric down icon.
/// </summary>
[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)
{ {
InputType = InputType.Number; InputType = InputType.Number;
} }
} }
private bool IsNumericType(string type) protected override void OnParametersSet()
{ {
switch (type.ToLower()) base.OnParametersSet();
{ // if input is to be debounced, makes sense to bind the change of the text to oninput
case "uint16": // so we set ChangeTextImmediately to true
case "uint32": if (TextChangeDelay > 0)
case "uint64": ChangeTextImmediately = true;
case "int16":
case "int32":
case "int64":
case "int":
case "double":
case "decimal":
case "float":
return true;
default:
return false;
}
} }
#endregion
/// <summary>
/// Sets the input text from outside programmatically
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
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<string> { }
}

@ -11,7 +11,7 @@
{ {
@if (AdornmentClick.HasDelegate) @if (AdornmentClick.HasDelegate)
{ {
<IconButton Icon="@Icon" OnClick="@AdornmentClick" Edge="@Edge" Size="@Size" Color="@Color" aria-label="@(!string.IsNullOrEmpty(AriaLabel) ? AriaLabel : "Icon Button")" tabindex="-1"/> <IconButton Icon="@Icon" Clicked="@AdornmentClick" Edge="@Edge" Size="@Size" Color="@Color" aria-label="@(!string.IsNullOrEmpty(AriaLabel) ? AriaLabel : "Icon Button")" tabindex="-1" />
} }
else else
{ {

@ -39,7 +39,7 @@ public abstract class InputBase<T> : FormComponent<T, string>
/// </summary> /// </summary>
[Parameter] [Parameter]
[Category(CategoryTypes.FormComponent.Behavior)] [Category(CategoryTypes.FormComponent.Behavior)]
public bool Immediate { get; set; } public bool ChangeTextImmediately { get; set; } = true;
/// <summary> /// <summary>
/// If true, the input will not have an underline. /// If true, the input will not have an underline.
@ -170,7 +170,7 @@ public abstract class InputBase<T> : FormComponent<T, string>
/// </summary> /// </summary>
[Parameter] [Parameter]
[Category(CategoryTypes.FormComponent.Behavior)] [Category(CategoryTypes.FormComponent.Behavior)]
public int Lines { get; set; } = 1; public int NumberOfLines { get; set; } = 1;
/// <summary> /// <summary>
/// The text to be displayed. /// The text to be displayed.

@ -15,10 +15,10 @@
</div> </div>
} }
<input @ref="_elementReferenceStart" @attributes="CustomAttributes" type="@InputTypeString" class="@InputClassname" @bind-value="@TextStart" @bind-value:event="@((Immediate ? "oninput" : "onchange"))" <input @ref="_elementReferenceStart" @attributes="CustomAttributes" type="@InputTypeString" class="@InputClassname" @bind-value="@TextStart" @bind-value:event="@((ChangeTextImmediately ? "oninput" : "onchange"))"
placeholder="@PlaceholderStart" disabled=@Disabled readonly="@ReadOnly" @onblur="@OnBlurred" @onkeydown="@InvokeKeyDown" @onkeypress="@InvokeKeyPress" @onkeyup="@InvokeKeyUp" inputmode="@InputMode.ToString()" pattern="@Pattern" /> placeholder="@PlaceholderStart" disabled=@Disabled readonly="@ReadOnly" @onblur="@OnBlurred" @onkeydown="@InvokeKeyDown" @onkeypress="@InvokeKeyPress" @onkeyup="@InvokeKeyUp" inputmode="@InputMode.ToString()" pattern="@Pattern" />
<Icon Class="range-input-separator mud-flip-x-rtl" Icon="@SeparatorIcon" Color="@ThemeColor.Default" /> <Icon Class="range-input-separator mud-flip-x-rtl" Icon="@SeparatorIcon" Color="@ThemeColor.Default" />
<input @ref="_elementReferenceEnd" @attributes="CustomAttributes" type="@InputTypeString" class="@InputClassname" @bind-value="@TextEnd" @bind-value:event="@((Immediate ? "oninput" : "onchange"))" inputmode="@InputMode.ToString()" pattern="@Pattern" <input @ref="_elementReferenceEnd" @attributes="CustomAttributes" type="@InputTypeString" class="@InputClassname" @bind-value="@TextEnd" @bind-value:event="@((ChangeTextImmediately ? "oninput" : "onchange"))" inputmode="@InputMode.ToString()" pattern="@Pattern"
placeholder="@PlaceholderEnd" disabled=@Disabled readonly="@ReadOnly" @onblur="@OnBlurred" @onkeydown="@InvokeKeyDown" @onkeypress="@InvokeKeyPress" @onkeyup="@InvokeKeyUp" /> placeholder="@PlaceholderEnd" disabled=@Disabled readonly="@ReadOnly" @onblur="@OnBlurred" @onkeydown="@InvokeKeyDown" @onkeypress="@InvokeKeyPress" @onkeyup="@InvokeKeyUp" />
@if (Adornment == Adornment.End) @if (Adornment == Adornment.End)

@ -58,7 +58,7 @@
Color="@ThemeColor.Default" Color="@ThemeColor.Default"
Icon="@ClearIcon" Icon="@ClearIcon"
Size="@Size.Small" Size="@Size.Small"
OnClick="@HandleClearButton"/> Clicked="@HandleClearButton" />
} }
@if (Adornment == Adornment.End) @if (Adornment == Adornment.End)

@ -33,7 +33,7 @@
} }
else else
{ {
<IconButton Variant="@Variant" Icon="@Icon" Color="@Color" Size="@Size" Disabled="@Disabled" DisableRipple="@DisableRipple" DisableElevation="@DisableElevation" @onclick="@ToggleMenu" @ontouchend="@(ActivationEvent == MouseEvent.RightClick ? ToggleMenuTouch : null)" @oncontextmenu="@(ActivationEvent==MouseEvent.RightClick ? ToggleMenu : null)" /> <IconButton Variant="@Variant" Icon="@Icon" Color="@Color" Size="@Size" Disabled="@Disabled" DisableRipple="@DisableRipple" DisableElevation="@DisableElevation" Clicked="@ToggleMenu" @ontouchend="@(ActivationEvent == MouseEvent.RightClick ? ToggleMenuTouch : null)" @oncontextmenu="@(ActivationEvent==MouseEvent.RightClick ? ToggleMenu : null)" />
} }
@* The portal has to include the cascading values inside, because it's not able to teletransport the cascade *@ @* The portal has to include the cascading values inside, because it's not able to teletransport the cascade *@
<Popover Open="@_isOpen" Class="@PopoverClass" MaxHeight="@MaxHeight" AnchorOrigin="@AnchorOrigin" TransformOrigin="@TransformOrigin" RelativeWidth="@FullWidth" Style="@PopoverStyle"> <Popover Open="@_isOpen" Class="@PopoverClass" MaxHeight="@MaxHeight" AnchorOrigin="@AnchorOrigin" TransformOrigin="@TransformOrigin" RelativeWidth="@FullWidth" Style="@PopoverStyle">

@ -39,7 +39,7 @@
AdornmentColor="@AdornmentColor" AdornmentColor="@AdornmentColor"
IconSize="@IconSize" IconSize="@IconSize"
Error="@HasError" Error="@HasError"
Immediate="@(Immediate)" ChangeTextImmediately="@(ChangeTextImmediately)"
Margin="@Margin" Margin="@Margin"
MaxLength="@MaxLength" MaxLength="@MaxLength"
HideSpinButtons="@HideSpinButtons" HideSpinButtons="@HideSpinButtons"

@ -6,13 +6,13 @@
@if (ShowFirstButton) @if (ShowFirstButton)
{ {
<li class="@ItemClassname"> <li class="@ItemClassname">
<IconButton Icon="@FirstIcon" Size="@Size" Variant="@Variant" Disabled="@(Selected == 1 || Disabled)" OnClick="@(() => OnClickControlButton(Page.First))" aria-label="First page"></IconButton> <IconButton Icon="@FirstIcon" Size="@Size" Variant="@Variant" Disabled="@(Selected == 1 || Disabled)" Clicked="@(() => OnClickControlButton(Page.First))" aria-label="First page"></IconButton>
</li> </li>
} }
@if (ShowPreviousButton) @if (ShowPreviousButton)
{ {
<li class="@ItemClassname"> <li class="@ItemClassname">
<IconButton Icon="@BeforeIcon" Size="@Size" Variant="@Variant" Disabled="@(Selected == 1 || Disabled)" OnClick="@(() => OnClickControlButton(Page.Previous))" aria-label="Previous page"></IconButton> <IconButton Icon="@BeforeIcon" Size="@Size" Variant="@Variant" Disabled="@(Selected == 1 || Disabled)" Clicked="@(() => OnClickControlButton(Page.Previous))" aria-label="Previous page"></IconButton>
</li> </li>
} }
@foreach (var state in GeneratePagination()) @foreach (var state in GeneratePagination())
@ -32,20 +32,20 @@
} }
else { else {
<li class="@ItemClassname"> <li class="@ItemClassname">
<Button OnClick="@(() => Selected = currentPage)" Variant="@Variant" Size="@Size" DisableRipple="true" Disabled="@Disabled" aria-label="@($"Page {currentPage}")">@currentPage</Button> <Button Clicked="@(() => Selected = currentPage)" Variant="@Variant" Size="@Size" DisableRipple="true" Disabled="@Disabled" aria-label="@($"Page {currentPage}")">@currentPage</Button>
</li> </li>
} }
} }
@if (ShowNextButton) @if (ShowNextButton)
{ {
<li class="@ItemClassname"> <li class="@ItemClassname">
<IconButton Icon="@NextIcon" Variant="@Variant" Size="@Size" Disabled="@(Selected == Count || Disabled)" OnClick="@(() => OnClickControlButton(Page.Next))" aria-label="Next page"></IconButton> <IconButton Icon="@NextIcon" Variant="@Variant" Size="@Size" Disabled="@(Selected == Count || Disabled)" Clicked="@(() => OnClickControlButton(Page.Next))" aria-label="Next page"></IconButton>
</li> </li>
} }
@if (ShowLastButton) @if (ShowLastButton)
{ {
<li class="@ItemClassname"> <li class="@ItemClassname">
<IconButton Icon="@LastIcon" Variant="@Variant" Size="@Size" Disabled="@(Selected == Count || Disabled)" OnClick="@(() => OnClickControlButton(Page.Last))" aria-label="Last page"></IconButton> <IconButton Icon="@LastIcon" Variant="@Variant" Size="@Size" Disabled="@(Selected == Count || Disabled)" Clicked="@(() => OnClickControlButton(Page.Last))" aria-label="Last page"></IconButton>
</li> </li>
} }
</Element> </Element>

@ -39,7 +39,7 @@
</div> </div>
} }
<input class="slider-input" aria-valuenow="@Value" aria-valuemin="@_min" aria-valuemax="@_max" role="slider" @attributes="CustomAttributes" type="range" min="@_min" max="@_max" step="@_step" disabled="@Disabled" <input class="slider-input" aria-valuenow="@Value" aria-valuemin="@_min" aria-valuemax="@_max" role="slider" @attributes="CustomAttributes" type="range" min="@_min" max="@_max" step="@_step" disabled="@Disabled"
@bind-value="@Text" @bind-value:event="@((Immediate == true ? "oninput" : "onchange"))" /> @bind-value="@Text" @bind-value:event="@((ChangeImmediately == true ? "oninput" : "onchange"))" />
@if (ValueLabel) @if (ValueLabel)
{ {
<div class="slider-value-label" style="@($"left:{width}%;")"> <div class="slider-value-label" style="@($"left:{width}%;")">

@ -117,7 +117,7 @@ public partial class Slider<T> : UIComponent
/// </summary> /// </summary>
[Parameter] [Parameter]
[Category(CategoryTypes.Slider.Behavior)] [Category(CategoryTypes.Slider.Behavior)]
public bool Immediate { get; set; } = true; public bool ChangeImmediately { get; set; } = true;
/// <summary> /// <summary>
/// If true, displays the slider vertical. /// If true, displays the slider vertical.

@ -23,12 +23,12 @@
@if (ShowActionButton) @if (ShowActionButton)
{ {
<Button Variant="@ActionVariant" Color="@ActionColor" OnClick="ActionClicked" DisableElevation>@Action</Button> <Button Variant="@ActionVariant" Color="@ActionColor" Clicked="ActionClicked" DisableElevation>@Action</Button>
} }
@if (ShowCloseIcon) @if (ShowCloseIcon)
{ {
<IconButton Icon="@CloseIcon" Size="Size.Small" Class="ms-2" OnClick="CloseIconClicked" /> <IconButton Icon="@CloseIcon" Size="Size.Small" Class="ms-2" Clicked="CloseIconClicked" />
} }
</div> </div>
} }

@ -13,7 +13,7 @@
<div class="d-flex"> <div class="d-flex">
@if (GroupDefinition.Expandable) @if (GroupDefinition.Expandable)
{ {
<IconButton Class="table-row-expander" Icon="@(IsExpanded ? ExpandIcon : CollapseIcon)" OnClick="@(() => IsExpanded = !IsExpanded)"/> <IconButton Class="table-row-expander" Icon="@(IsExpanded ? ExpandIcon : CollapseIcon)" Clicked="@(() => IsExpanded = !IsExpanded)" />
} }
else else
{ {

@ -34,10 +34,10 @@
@if (!HidePagination) @if (!HidePagination)
{ {
<div class="table-pagination-actions"> <div class="table-pagination-actions">
<IconButton Class="flip-x-rtl" Icon="@FirstIcon" Disabled="@BackButtonsDisabled" @onclick="@(() => Table.NavigateTo(Page.First))" aria-label="First page" /> <IconButton Class="flip-x-rtl" Icon="@FirstIcon" Disabled="@BackButtonsDisabled" Clicked="@(() => Table.NavigateTo(Page.First))" aria-label="First page" />
<IconButton Class="flip-x-rtl" Icon="@BeforeIcon" Disabled="@BackButtonsDisabled" @onclick="@(() => Table.NavigateTo(Page.Previous))" aria-label="Previous page" /> <IconButton Class="flip-x-rtl" Icon="@BeforeIcon" Disabled="@BackButtonsDisabled" Clicked="@(() => Table.NavigateTo(Page.Previous))" aria-label="Previous page" />
<IconButton Class="flip-x-rtl" Icon="@NextIcon" Disabled="@ForwardButtonsDisabled" @onclick="@(() => Table.NavigateTo(Page.Next))" aria-label="Next page" /> <IconButton Class="flip-x-rtl" Icon="@NextIcon" Disabled="@ForwardButtonsDisabled" Clicked="@(() => Table.NavigateTo(Page.Next))" aria-label="Next page" />
<IconButton Class="flip-x-rtl" Icon="@LastIcon" Disabled="@ForwardButtonsDisabled" @onclick="@(() => Table.NavigateTo(Page.Last))" aria-label="Last page" /> <IconButton Class="flip-x-rtl" Icon="@LastIcon" Disabled="@ForwardButtonsDisabled" Clicked="@(() => Table.NavigateTo(Page.Last))" aria-label="Last page" />
</div> </div>
} }
@if (HorizontalAlignment == HorizontalAlignment.Start || @if (HorizontalAlignment == HorizontalAlignment.Start ||

@ -15,19 +15,19 @@
} }
else else
{ {
<IconButton Size="@Size.Small" Icon="@Icons.Outlined.Edit" Class="pa-0" OnClick="StartEditingItem" Disabled="Context.EditButtonDisabled(Item)" /> <IconButton Size="@Size.Small" Icon="@Icons.Outlined.Edit" Class="pa-0" Clicked="StartEditingItem" Disabled="Context.EditButtonDisabled(Item)" />
} }
} }
else if (object.ReferenceEquals(Context?.Table._editingItem, Item) && (!Context?.Table.ReadOnly ?? false) && Context?.Table.ApplyButtonPosition.DisplayApplyButtonAtStart() == true) else if (object.ReferenceEquals(Context?.Table._editingItem, Item) && (!Context?.Table.ReadOnly ?? false) && Context?.Table.ApplyButtonPosition.DisplayApplyButtonAtStart() == true)
{ {
<div style="display: flex;"> <div style="display: flex;">
<Tooltip Text="@Context.Table.CommitEditTooltip"> <Tooltip Text="@Context.Table.CommitEditTooltip">
<IconButton Class="pa-0" Icon="@Context.Table.CommitEditIcon" OnClick="FinishEdit" Size="@Size.Small" Disabled="@(!(Context?.Table.Validator?.IsValid ?? false))" /> <IconButton Class="pa-0" Icon="@Context.Table.CommitEditIcon" Clicked="FinishEdit" Size="@Size.Small" Disabled="@(!(Context?.Table.Validator?.IsValid ?? false))" />
</Tooltip> </Tooltip>
@if (Context.Table.CanCancelEdit) @if (Context.Table.CanCancelEdit)
{ {
<Tooltip Text="@Context.Table.CancelEditTooltip"> <Tooltip Text="@Context.Table.CancelEditTooltip">
<IconButton Class="pa-0 ml-4" Icon="@Context.Table.CancelEditIcon" OnClick="CancelEdit" Size="@Size.Small" /> <IconButton Class="pa-0 ml-4" Icon="@Context.Table.CancelEditIcon" Clicked="CancelEdit" Size="@Size.Small" />
</Tooltip> </Tooltip>
} }
</div> </div>
@ -58,19 +58,19 @@
} }
else else
{ {
<IconButton Size="@Size.Small" Icon="@Icons.Outlined.Edit" Class="pa-0" OnClick="StartEditingItem" Disabled="Context.EditButtonDisabled(Item)" /> <IconButton Size="@Size.Small" Icon="@Icons.Outlined.Edit" Class="pa-0" Clicked="StartEditingItem" Disabled="Context.EditButtonDisabled(Item)" />
} }
} }
else if (object.ReferenceEquals(Context?.Table._editingItem, Item) && (!Context?.Table.ReadOnly ?? false) && Context?.Table.ApplyButtonPosition.DisplayApplyButtonAtEnd() == true) else if (object.ReferenceEquals(Context?.Table._editingItem, Item) && (!Context?.Table.ReadOnly ?? false) && Context?.Table.ApplyButtonPosition.DisplayApplyButtonAtEnd() == true)
{ {
<div style="display: flex;"> <div style="display: flex;">
<Tooltip Text="@Context.Table.CommitEditTooltip"> <Tooltip Text="@Context.Table.CommitEditTooltip">
<IconButton Class="pa-0" Icon="@Context.Table.CommitEditIcon" OnClick="FinishEdit" Size="@Size.Small" Disabled="@(!(Context?.Table.Validator?.IsValid ?? false))" /> <IconButton Class="pa-0" Icon="@Context.Table.CommitEditIcon" Clicked="FinishEdit" Size="@Size.Small" Disabled="@(!(Context?.Table.Validator?.IsValid ?? false))" />
</Tooltip> </Tooltip>
@if (Context.Table.CanCancelEdit) @if (Context.Table.CanCancelEdit)
{ {
<Tooltip Text="@Context.Table.CancelEditTooltip"> <Tooltip Text="@Context.Table.CancelEditTooltip">
<MudIconButton Class="pa-0 ml-4" Icon="@Context.Table.CancelEditIcon" OnClick="CancelEdit" Size="@Size.Small" /> <IconButton Class="pa-0 ml-4" Icon="@Context.Table.CancelEditIcon" Clicked="CancelEdit" Size="@Size.Small" />
</Tooltip> </Tooltip>
} }
</div> </div>

@ -15,12 +15,12 @@
if (string.IsNullOrEmpty(AddIconToolTip) == false) if (string.IsNullOrEmpty(AddIconToolTip) == false)
{ {
<Tooltip Text="@AddIconToolTip"> <Tooltip Text="@AddIconToolTip">
<IconButton Icon="@AddTabIcon" Class="@AddIconClass" Style="@AddIconStyle" OnClick="@AddTab" /> <IconButton Icon="@AddTabIcon" Class="@AddIconClass" Style="@AddIconStyle" Clicked="@AddTab" />
</Tooltip> </Tooltip>
} }
else else
{ {
<IconButton Icon="@AddTabIcon" Class="@AddIconClass" Style="@AddIconStyle" OnClick="@AddTab" /> <IconButton Icon="@AddTabIcon" Class="@AddIconClass" Style="@AddIconStyle" Clicked="@AddTab" />
} }
} }
; ;
@ -30,12 +30,12 @@
if (string.IsNullOrEmpty(CloseIconToolTip) == false) if (string.IsNullOrEmpty(CloseIconToolTip) == false)
{ {
<Tooltip Text="@CloseIconToolTip"> <Tooltip Text="@CloseIconToolTip">
<IconButton Icon="@CloseTabIcon" Class="@CloseIconClass" Style="@CloseIconStyle" OnClick="EventCallback.Factory.Create<MouseEventArgs>(this, () => CloseTab.InvokeAsync(context))" /> <IconButton Icon="@CloseTabIcon" Class="@CloseIconClass" Style="@CloseIconStyle" Clicked="EventCallback.Factory.Create<MouseEventArgs>(this, () => CloseTab.InvokeAsync(context))" />
</Tooltip> </Tooltip>
} }
else else
{ {
<IconButton Icon="@CloseTabIcon" Class="@CloseIconClass" Style="@CloseIconStyle" OnClick="EventCallback.Factory.Create<MouseEventArgs>(this, () => CloseTab.InvokeAsync(context))" /> <IconButton Icon="@CloseTabIcon" Class="@CloseIconClass" Style="@CloseIconStyle" Clicked="EventCallback.Factory.Create<MouseEventArgs>(this, () => CloseTab.InvokeAsync(context))" />
} }
} }
; ;

@ -14,7 +14,7 @@
@if (_showScrollButtons) @if (_showScrollButtons)
{ {
<div class="tabs-scroll-button"> <div class="tabs-scroll-button">
<GlyphButton Icon="@_prevIcon" Color="@ScrollIconColor" Clicked="@((e) => ScrollPrev())" Disabled="@_prevButtonDisabled" /> <IconButton Icon="@_prevIcon" Color="@ScrollIconColor" Clicked="@((e) => ScrollPrev())" Disabled="@_prevButtonDisabled" />
</div> </div>
} }
<div @ref="@_tabsContentSize" class="tabs-toolbar-content"> <div @ref="@_tabsContentSize" class="tabs-toolbar-content">
@ -52,7 +52,7 @@
@if (_showScrollButtons) @if (_showScrollButtons)
{ {
<div class="tabs-scroll-button"> <div class="tabs-scroll-button">
<GlyphButton Icon="@_nextIcon" Color="@ScrollIconColor" Clicked="@((e) => ScrollNext())" Disabled="@_nextButtonDisabled" /> <IconButton Icon="@_nextIcon" Color="@ScrollIconColor" Clicked="@((e) => ScrollNext())" Disabled="@_nextButtonDisabled" />
</div> </div>
} }
@if (HeaderPosition == TabHeaderPosition.After && Header != null) @if (HeaderPosition == TabHeaderPosition.After && Header != null)

@ -25,7 +25,7 @@
@ref="InputReference" @ref="InputReference"
@attributes="CustomAttributes" @attributes="CustomAttributes"
InputType="@InputType" InputType="@InputType"
Lines="@Lines" NumberOfLines="@NumberOfLines"
Variant="@Variant" Variant="@Variant"
TextUpdateSuppression="@TextUpdateSuppression" TextUpdateSuppression="@TextUpdateSuppression"
Value="@Text" Value="@Text"
@ -44,7 +44,7 @@
OnAdornmentClick="@OnAdornmentClick" OnAdornmentClick="@OnAdornmentClick"
Error="@HasError" Error="@HasError"
ErrorId="@ErrorId" ErrorId="@ErrorId"
Immediate="@Immediate" ChangeTextImmediately="@ChangeTextImmediately"
Margin="@Margin" Margin="@Margin"
OnBlur="@OnBlurred" OnBlur="@OnBlurred"
OnKeyDown="@InvokeKeyDown" OnKeyDown="@InvokeKeyDown"
@ -65,7 +65,7 @@
@attributes="CustomAttributes" @attributes="CustomAttributes"
Mask="@_mask" Mask="@_mask"
InputType="@InputType" InputType="@InputType"
Lines="@Lines" NumberOfLines="@NumberOfLines"
Variant="@Variant" Variant="@Variant"
TextUpdateSuppression="@TextUpdateSuppression" TextUpdateSuppression="@TextUpdateSuppression"
Value="@Text" Value="@Text"
@ -82,7 +82,7 @@
IconSize="@IconSize" IconSize="@IconSize"
OnAdornmentClick="@OnAdornmentClick" OnAdornmentClick="@OnAdornmentClick"
Error="@HasError" Error="@HasError"
Immediate="@Immediate" ChangeTextImmediately="@ChangeTextImmediately"
Margin="@Margin" Margin="@Margin"
OnBlur="@OnBlurred" OnBlur="@OnBlurred"
Clearable="@Clearable" Clearable="@Clearable"

@ -5,7 +5,7 @@
<div class="treeview-item-arrow"> <div class="treeview-item-arrow">
@if (Visible) @if (Visible)
{ {
<IconButton OnClick="@ToggleAsync" Icon="@(Loading ? LoadingIcon : ExpandedIcon)" Color="@(Loading ? LoadingIconColor : ExpandedIconColor)" Class="@Classname"></IconButton> <IconButton Clicked="@ToggleAsync" Icon="@(Loading ? LoadingIcon : ExpandedIcon)" Color="@(Loading ? LoadingIconColor : ExpandedIconColor)" Class="@Classname"></IconButton>
} }
</div> </div>

@ -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;
}
}
}
Loading…
Cancel
Save