@libs-ui/components-inputs-keyboard
v0.2.357-5
Published
> Component bàn phím số (Numeric Keypad) hỗ trợ nhập liệu bằng chuột và bàn phím cứng (phím số 0-9).
Readme
@libs-ui/components-inputs-keyboard
Component bàn phím số (Numeric Keypad) hỗ trợ nhập liệu bằng chuột và bàn phím cứng (phím số 0-9).
Giới thiệu
LibsUiComponentsInputsKeyboardComponent cung cấp giao diện bàn phím số tiêu chuẩn gồm các phím 0–9, * và #. Component tự động lắng nghe sự kiện keyup toàn cục trên document, cho phép người dùng nhập liệu đồng bộ cả từ UI lẫn bàn phím cứng. Mỗi lần nhấn phím, component emit mã code tương ứng ra ngoài qua output outKeyCodeSelected, phù hợp cho các màn hình nhập mã PIN, quay số tổng đài hoặc thiết bị cảm ứng.
Tính năng
- ✅ Giao diện bàn phím số tiêu chuẩn (1–9,
*,0,#) - ✅ Đồng bộ tự động với bàn phím cứng (phím số 0–9, cả hàng số chính và numpad)
- ✅ Hiển thị chuỗi đã nhập nội bộ trực tiếp trên bàn phím
- ✅ Emit mã code phím đã chọn qua output event
outKeyCodeSelected - ✅ Sử dụng Angular Signals — hiệu năng cao với
ChangeDetectiontối ưu - ✅ Standalone component — dễ tích hợp, không cần NgModule
Khi nào sử dụng
- Màn hình nhập mã PIN hoặc mật khẩu chỉ có số
- Ứng dụng tổng đài (Dialer/VoIP) cần giao diện quay số
- Thiết bị cảm ứng (POS, kiosk) cần bàn phím số lớn dễ bấm
- Cần đồng bộ giữa thao tác click chuột và bàn phím cứng
Cài đặt
npm install @libs-ui/components-inputs-keyboardImport
import { LibsUiComponentsInputsKeyboardComponent } from '@libs-ui/components-inputs-keyboard';
@Component({
standalone: true,
imports: [LibsUiComponentsInputsKeyboardComponent],
// ...
})
export class YourComponent {}Các exports phụ trợ (interface, define) cũng có thể import từ cùng package:
import {
LibsUiComponentsInputsKeyboardComponent,
IKeyCode,
keypadConfig,
} from '@libs-ui/components-inputs-keyboard';Ví dụ sử dụng
Ví dụ 1 — Cơ bản
Hiển thị bàn phím số và log mã phím mỗi lần nhấn.
<!-- template.html -->
<libs_ui-components-inputs-keyboard
(outKeyCodeSelected)="handlerKeySelect($event)"
/>// component.ts
import { Component } from '@angular/core';
import { LibsUiComponentsInputsKeyboardComponent } from '@libs-ui/components-inputs-keyboard';
@Component({
selector: 'app-pin-entry',
standalone: true,
imports: [LibsUiComponentsInputsKeyboardComponent],
templateUrl: './pin-entry.component.html',
})
export class PinEntryComponent {
handlerKeySelect(event: Event, code: string): void {
// Lưu ý: outKeyCodeSelected truyền string trực tiếp, không phải DOM Event
// Handler này nhận code: string từ output
}
}Vì
outKeyCodeSelectedemit kiểustring(không phảiEvent), handler nhận thẳngstring:
handlerKeySelect(code: string): void {
console.log('Phím được nhấn:', code);
}Ví dụ 2 — Xây dựng chuỗi PIN
Tích lũy các phím đã nhấn để tạo chuỗi PIN, kết hợp nút xóa.
<!-- template.html -->
<div class="max-w-[300px] border rounded-xl p-4 bg-white shadow-sm">
<div class="text-center text-2xl font-mono tracking-widest mb-4 min-h-[36px]">
{{ pinDisplay() }}
</div>
<libs_ui-components-inputs-keyboard
(outKeyCodeSelected)="handlerPinKey($event)"
/>
<button class="mt-4 w-full text-sm text-red-500" (click)="handlerClearPin($event)">
Xóa
</button>
</div>// component.ts
import { Component, signal } from '@angular/core';
import { LibsUiComponentsInputsKeyboardComponent } from '@libs-ui/components-inputs-keyboard';
@Component({
selector: 'app-pin-input',
standalone: true,
imports: [LibsUiComponentsInputsKeyboardComponent],
templateUrl: './pin-input.component.html',
})
export class PinInputComponent {
private pinValue = signal<string>('');
protected pinDisplay = signal<string>('');
handlerPinKey(code: string): void {
if (this.pinValue().length >= 6) return;
this.pinValue.update((prev) => prev + code);
this.pinDisplay.set('*'.repeat(this.pinValue().length));
}
handlerClearPin(event: Event): void {
event.stopPropagation();
this.pinValue.set('');
this.pinDisplay.set('');
}
}Ví dụ 3 — Theo dõi từng phím và toàn bộ chuỗi
Hiển thị phím vừa nhấn và chuỗi đầy đủ theo thời gian thực.
<!-- template.html -->
<div class="flex gap-8 items-start">
<div class="w-[280px] bg-slate-50 p-6 rounded-2xl border border-slate-200">
<libs_ui-components-inputs-keyboard
(outKeyCodeSelected)="handlerKeySelect($event)"
/>
</div>
<div class="flex-1 space-y-4 pt-4">
<div class="bg-blue-50 p-4 rounded-lg border border-blue-100">
<p class="text-sm text-blue-600 font-medium mb-1">Phím vừa nhấn:</p>
<div class="text-3xl font-bold text-blue-900">{{ lastKey() || '-' }}</div>
</div>
<div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
<p class="text-sm text-gray-600 font-medium mb-1">Chuỗi đầy đủ:</p>
<div class="text-xl font-mono text-gray-800 break-all">{{ fullSequence() || '...' }}</div>
<button class="mt-2 text-xs text-red-500 hover:underline" (click)="handlerClear($event)">
Xóa lịch sử
</button>
</div>
</div>
</div>// component.ts
import { Component, signal } from '@angular/core';
import { LibsUiComponentsInputsKeyboardComponent } from '@libs-ui/components-inputs-keyboard';
@Component({
selector: 'app-keyboard-demo',
standalone: true,
imports: [LibsUiComponentsInputsKeyboardComponent],
templateUrl: './keyboard-demo.component.html',
})
export class KeyboardDemoComponent {
protected lastKey = signal<string>('');
protected fullSequence = signal<string>('');
handlerKeySelect(code: string): void {
this.lastKey.set(code);
this.fullSequence.update((prev) => prev + code);
}
handlerClear(event: Event): void {
event.stopPropagation();
this.lastKey.set('');
this.fullSequence.set('');
}
}@Input()
Component hiện tại không có @Input() công khai. Toàn bộ cấu hình phím được quản lý nội bộ thông qua keypadConfig() — mảng mặc định 12 phím: 1, 2, 3, 4, 5, 6, 7, 8, 9, *, 0, #.
@Output()
| Output | Type | Mô tả | Handler TS | Binding HTML |
|---|---|---|---|---|
| (outKeyCodeSelected) | string | Emit mã code của phím khi người dùng click vào phím trên UI hoặc nhấn phím số trên bàn phím cứng (0–9) | handlerKeySelect(code: string): void { /* xử lý */ } | (outKeyCodeSelected)="handlerKeySelect($event)" |
Lưu ý về handler: Output emit thẳng string (không phải DOM Event), nên handler nhận tham số kiểu string. Nếu cần event.stopPropagation(), hãy gắn lên sự kiện DOM bao ngoài (không phải output này).
Types & Interfaces
import { IKeyCode, keypadConfig } from '@libs-ui/components-inputs-keyboard';IKeyCode
Cấu hình thông tin một phím bấm trên bàn phím.
interface IKeyCode {
/** Mã định danh của phím — VD: '1', '0', '*', '#' */
code: string;
/** Nhãn hiển thị của phím trên giao diện */
label: string;
}keypadConfig()
Hàm factory trả về mảng cấu hình 12 phím mặc định.
import { keypadConfig } from '@libs-ui/components-inputs-keyboard';
// Trả về IKeyCode[] gồm: 1, 2, 3, 4, 5, 6, 7, 8, 9, *, 0, #
const keys: IKeyCode[] = keypadConfig();Lưu ý quan trọng
⚠️ Lắng nghe phím cứng toàn cục: Component đăng ký lắng nghe sự kiện document:keyup khi được mount. Nếu nhiều instance libs_ui-components-inputs-keyboard cùng tồn tại trong DOM, tất cả đều sẽ nhận và xử lý sự kiện bàn phím đồng thời.
⚠️ Phạm vi phím cứng hỗ trợ: Chỉ lắng nghe phím số 0–9 từ bàn phím cứng (cả hàng số chính keyCode 48–57 và numpad keyCode 96–105). Các phím * và # chỉ có thể nhập bằng cách click trực tiếp trên UI.
⚠️ State hiển thị nội bộ: Chuỗi ký tự hiển thị trên bàn phím (resultSelectKey) được quản lý hoàn toàn nội bộ bởi component và không bị reset tự động. Nếu cần reset, hãy destroy và tạo lại component (ví dụ: dùng @if để unmount/remount).
⚠️ Không có @Input() cấu hình phím: Cấu hình danh sách phím hiện tại được hardcode nội bộ qua keypadConfig(). Không thể tùy biến danh sách phím từ bên ngoài thông qua input binding.
Demo
npx nx serve core-uiTruy cập: http://localhost:4500/inputs/keyboard
Unit Tests
# Chạy tests cho lib
npx nx test components-inputs-keyboard
# Chạy test một file cụ thể
npx nx test components-inputs-keyboard --testFile=libs-ui/components/inputs/keyboard/src/keyboard.component.spec.ts
# Chạy với coverage
npx nx test components-inputs-keyboard --coverage