-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(components): add textbox component (#53)
* feat(textbox): init the component * feat(textbox): add the base styles * feat(textbox): add the `Label` parameter; add label styles * feat(textbox): add input wrapper styles * feat(textbox): add inner wrapper styles * feat(textbox): add input styles * fix(textbox): implement abstract base method * feat(textbox): add size styles * feat(textbox): add the radius styles * feat(textbox): add the disabled styles * feat(textbox): add the full-width styles * feat(textbox): add the `Placeholder` param * feat(component): add element ref capture * feat(input base): add the `FocusAsync` method to the API * fix(textbox): add missing `OnChangeAsync` * feat(textbox): add the `LabelPlacement` param * feat(input base): add the `OnBlur` param * feat(textbox): add label placement styles * feat(textbox): add detailed styles for the 'inside' label placement * feat(textbox): add the main wrapper for the 'outside' label placement * feat(textbox): add the 'label outside' styles * feat(textbox): add the `Variant` param; add variant styles * feat(input base): add the `OnFocus` event callback * feat(textbox): add colored variant styles * chore(components): nits * chore(textbox): add underlined & size compound styles * chore(textbox): adjust label scale * chore(textbox): adjust outlined & small styles; removed shadow for underlined variant * feat(textbox): add the `StartContent` and `EndContent` params * feat(textbox): add support of the clear button * feat(textbox): add (data)attributes * feat(textbox): add the `Type` param; add support of different input types * feat(textbox): add the `Description` param; add helper wrapper * feat(textbox): add the `Invalid` param; add support for error messages * chore(input): comment out the check for `ValueExpression` for the time being * chore(textbox): rename slot 'root' => 'base' * feat(textbox): add the `Required` param; add required styles * feat(textbox): add support for the slots styling * feat(textbox): add support for `oninput` or `onchange` behaviors * feat(textbox): add support for debounced value input * chore(textbox): add missing data attributes * fix(debounced input): debounce only if the delay is greater than zero * chore(debounced input): nits * feat(textbox): add `data-hidden` attribute for hidden input type * test(textbox): add tests; update tests for InputBase
- Loading branch information
1 parent
90b851c
commit 6b9b85c
Showing
15 changed files
with
1,635 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// Copyright (c) LumexUI 2024 | ||
// LumexUI licenses this file to you under the MIT license | ||
// See the license here https://github.com/LumexUI/lumexui/blob/main/LICENSE | ||
|
||
namespace LumexUI.Common; | ||
|
||
/// <summary> | ||
/// Specifies when the input component updates its value and triggers validation. | ||
/// </summary> | ||
public enum InputBehavior | ||
{ | ||
/// <summary> | ||
/// Updates the value and triggers validation | ||
/// on each input event (e.g., when the user types in the input field). | ||
/// </summary> | ||
OnInput, | ||
|
||
/// <summary> | ||
/// Updates the value and triggers validation | ||
/// on change events (e.g., when the input field loses focus or the user presses enter). | ||
/// </summary> | ||
OnChange | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// Copyright (c) LumexUI 2024 | ||
// LumexUI licenses this file to you under the MIT license | ||
// See the license here https://github.com/LumexUI/lumexui/blob/main/LICENSE | ||
|
||
using System.ComponentModel; | ||
|
||
namespace LumexUI.Common; | ||
|
||
/// <summary> | ||
/// Specifies the different types of input elements. | ||
/// </summary> | ||
public enum InputType | ||
{ | ||
/// <summary> | ||
/// A text input field. | ||
/// </summary> | ||
[Description( "text" )] | ||
Text, | ||
|
||
/// <summary> | ||
/// A password input field. | ||
/// </summary> | ||
[Description( "password" )] | ||
Password, | ||
|
||
/// <summary> | ||
/// An email input field. | ||
/// </summary> | ||
[Description( "email" )] | ||
Email, | ||
|
||
/// <summary> | ||
/// A hidden input field. | ||
/// </summary> | ||
[Description( "hidden" )] | ||
Hidden, | ||
|
||
/// <summary> | ||
/// A number input field. | ||
/// </summary> | ||
[Description( "number" )] | ||
Number, | ||
|
||
/// <summary> | ||
/// A search input field. | ||
/// </summary> | ||
[Description( "search" )] | ||
Search, | ||
|
||
/// <summary> | ||
/// A telephone input field. | ||
/// </summary> | ||
[Description( "tel" )] | ||
Telephone, | ||
|
||
/// <summary> | ||
/// A URL input field. | ||
/// </summary> | ||
[Description( "url" )] | ||
Url, | ||
|
||
/// <summary> | ||
/// A color input field. | ||
/// </summary> | ||
[Description( "color" )] | ||
Color, | ||
|
||
/// <summary> | ||
/// A date input field. | ||
/// </summary> | ||
[Description( "date" )] | ||
Date, | ||
|
||
/// <summary> | ||
/// A date-time input field (local time). | ||
/// </summary> | ||
[Description( "datetime-local" )] | ||
DateTimeLocal, | ||
|
||
/// <summary> | ||
/// A month input field. | ||
/// </summary> | ||
[Description( "month" )] | ||
Month, | ||
|
||
/// <summary> | ||
/// A time input field. | ||
/// </summary> | ||
[Description( "time" )] | ||
Time, | ||
|
||
/// <summary> | ||
/// A week input field. | ||
/// </summary> | ||
[Description( "week" )] | ||
Week | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Copyright (c) LumexUI 2024 | ||
// LumexUI licenses this file to you under the MIT license | ||
// See the license here https://github.com/LumexUI/lumexui/blob/main/LICENSE | ||
|
||
namespace LumexUI.Common; | ||
|
||
/// <summary> | ||
/// Specifies the different variants for an input component. | ||
/// </summary> | ||
public enum InputVariant | ||
{ | ||
/// <summary> | ||
/// A flat variant input. | ||
/// </summary> | ||
Flat, | ||
|
||
/// <summary> | ||
/// An outlined variant input. | ||
/// </summary> | ||
Outlined, | ||
|
||
/// <summary> | ||
/// An underlined variant input. | ||
/// </summary> | ||
Underlined | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
namespace LumexUI; | ||
|
||
/// <summary> | ||
/// Specifies the placement options for the label of an input component. | ||
/// </summary> | ||
public enum LabelPlacement | ||
{ | ||
/// <summary> | ||
/// Places the label inside the input component. | ||
/// </summary> | ||
Inside, | ||
|
||
/// <summary> | ||
/// Places the label outside the input component. | ||
/// </summary> | ||
Outside | ||
} |
125 changes: 125 additions & 0 deletions
125
src/LumexUI/Components/Bases/LumexDebouncedInputBase.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// Copyright (c) LumexUI 2024 | ||
// LumexUI licenses this file to you under the MIT license | ||
// See the license here https://github.com/LumexUI/lumexui/blob/main/LICENSE | ||
|
||
using Microsoft.AspNetCore.Components; | ||
|
||
namespace LumexUI; | ||
|
||
/// <summary> | ||
/// Represents a base class for input components with debounced value updates. | ||
/// </summary> | ||
/// <typeparam name="TValue">The type of the input value.</typeparam> | ||
public abstract class LumexDebouncedInputBase<TValue> : LumexInputBase<TValue>, IDisposable | ||
{ | ||
/// <summary> | ||
/// Gets or sets the delay, in milliseconds, for debouncing input events. | ||
/// </summary> | ||
[Parameter] public int DebounceDelay { get; set; } | ||
|
||
private readonly Debouncer _debouncer; | ||
|
||
private bool _disposed; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="LumexDebouncedInputBase{TValue}"/>. | ||
/// </summary> | ||
public LumexDebouncedInputBase() | ||
{ | ||
_debouncer = new Debouncer(); | ||
} | ||
|
||
/// <summary> | ||
/// Handles the input event asynchronously, applying a debounce delay if provided. | ||
/// </summary> | ||
/// <param name="args">The change event arguments.</param> | ||
/// <returns>A <see cref="Task"/> representing the asynchronous value input operation.</returns> | ||
protected virtual Task OnInputAsync( ChangeEventArgs args ) | ||
{ | ||
if( DebounceDelay != 0 ) | ||
{ | ||
return _debouncer.DebounceAsync( SetCurrentValueAsStringAsync, (string?)args.Value, DebounceDelay ); | ||
} | ||
|
||
return SetCurrentValueAsStringAsync( (string?)args.Value ); | ||
} | ||
|
||
/// <summary> | ||
/// Handles the change event asynchronously. | ||
/// </summary> | ||
/// <param name="args">The change event arguments.</param> | ||
/// <returns>A <see cref="Task"/> representing the asynchronous value change operation.</returns> | ||
protected virtual Task OnChangeAsync( ChangeEventArgs args ) | ||
{ | ||
return SetCurrentValueAsStringAsync( (string?)args.Value ); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public void Dispose() | ||
{ | ||
Dispose( disposing: true ); | ||
GC.SuppressFinalize( this ); | ||
} | ||
|
||
/// <inheritdoc cref="IDisposable.Dispose" /> | ||
protected virtual void Dispose( bool disposing ) | ||
{ | ||
if( !_disposed ) | ||
{ | ||
if( disposing ) | ||
{ | ||
_debouncer.Dispose(); | ||
} | ||
|
||
_disposed = true; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Represents a debouncer for handling debounced input events. | ||
/// </summary> | ||
private sealed class Debouncer : IDisposable | ||
{ | ||
private bool _disposed; | ||
private CancellationTokenSource? _cts; | ||
|
||
public async Task DebounceAsync( Func<string?, Task> workItem, string? arg, int milliseconds ) | ||
{ | ||
ArgumentNullException.ThrowIfNull( workItem ); | ||
|
||
_cts?.Cancel(); | ||
_cts?.Dispose(); | ||
|
||
var cts = _cts = new CancellationTokenSource(); | ||
using var timer = new PeriodicTimer( TimeSpan.FromMilliseconds( milliseconds ) ); | ||
|
||
while( await timer.WaitForNextTickAsync( cts.Token ) ) | ||
{ | ||
// Debounce time has passed without further input; trigger the debounced event | ||
await workItem( arg ); | ||
break; | ||
} | ||
} | ||
|
||
/// <inheritdoc /> | ||
public void Dispose() | ||
{ | ||
Dispose( disposing: true ); | ||
GC.SuppressFinalize( this ); | ||
} | ||
|
||
private void Dispose( bool disposing ) | ||
{ | ||
if( !_disposed ) | ||
{ | ||
if( disposing ) | ||
{ | ||
_cts?.Cancel(); | ||
_cts?.Dispose(); | ||
} | ||
|
||
_disposed = true; | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.