@*
EN: 6-digit OTP input with auto-focus, auto-advance, and backspace support.
VI: Input OTP 6 chữ số với auto-focus, tự chuyển ô, và hỗ trợ backspace.
*@
@inject IJSRuntime JS
@for (int i = 0; i < DigitCount; i++)
{
var index = i;
HandleInput(e, index)"
@onkeydown="(e) => HandleKeyDown(e, index)" />
}
@code {
private string[] _digits = new string[6];
///
/// EN: Number of OTP digits.
/// VI: Số chữ số OTP.
///
[Parameter] public int DigitCount { get; set; } = 6;
///
/// EN: Use blue theme (for 2FA authenticator).
/// VI: Dùng theme xanh dương (cho 2FA authenticator).
///
[Parameter] public bool UseBlueTheme { get; set; }
///
/// EN: Accessible group label for screen readers.
/// VI: Nhãn nhóm accessible cho screen reader.
///
[Parameter] public string GroupAriaLabel { get; set; } = "Enter OTP code";
///
/// EN: Callback when all digits are entered.
/// VI: Callback khi tất cả chữ số được nhập.
///
[Parameter] public EventCallback OnComplete { get; set; }
protected override void OnInitialized()
{
_digits = new string[DigitCount];
}
private async Task HandleInput(ChangeEventArgs e, int index)
{
var value = e.Value?.ToString() ?? "";
// EN: Only allow numeric input
// VI: Chỉ cho phép nhập số
if (!string.IsNullOrEmpty(value) && !char.IsDigit(value[0]))
{
_digits[index] = "";
return;
}
_digits[index] = value;
if (!string.IsNullOrEmpty(value) && index < DigitCount - 1)
{
// EN: Auto-advance to next input
// VI: Tự động chuyển sang ô tiếp theo
await JS.InvokeVoidAsync("focusOtpInput", index + 1);
}
// EN: Check if all digits are filled
// VI: Kiểm tra tất cả ô đã nhập xong chưa
if (_digits.All(d => !string.IsNullOrEmpty(d)))
{
var code = string.Join("", _digits);
await OnComplete.InvokeAsync(code);
}
}
private async Task HandleKeyDown(KeyboardEventArgs e, int index)
{
if (e.Key == "Backspace" && string.IsNullOrEmpty(_digits[index]) && index > 0)
{
// EN: Move to previous input on backspace
// VI: Chuyển về ô trước khi nhấn backspace
_digits[index - 1] = "";
await JS.InvokeVoidAsync("focusOtpInput", index - 1);
}
}
}