@libs-ui/components-inputs-keyboard 0.2.355-9 → 0.2.356-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,102 @@
1
- # inputs-keyboard
1
+ # @libs-ui/components-inputs-keyboard
2
2
 
3
- This library was generated with [Nx](https://nx.dev).
3
+ > 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.
4
+
5
+ ## Giới thiệu
6
+
7
+ `LibsUiComponentsInputsKeyboardComponent` cung cấp giao diện bàn phím số trực quan (0-9, \*, #). Component này tự động lắng nghe các sự kiện từ bàn phím cứng của người dùng để đồng bộ hóa việc nhập liệu, phù hợp cho các màn hình nhập mã PIN, mật khẩu số hoặc các ứng dụng Dialer.
8
+
9
+ ### Tính năng
10
+
11
+ - ✅ Giao diện bàn phím số tiêu chuẩn (0-9, \*, #)
12
+ - ✅ Đồng bộ hóa tự động với bàn phím cứng (0-9)
13
+ - ✅ Hiển thị kết quả nhập liệu nội bộ trực quan
14
+ - ✅ Emit mã code phím đã chọn qua output event
15
+ - ✅ Sử dụng Angular Signals cho hiệu năng cao
16
+ - ✅ Thiết kế Responsive, dễ dàng tích hợp
17
+
18
+ ## Khi nào sử dụng
19
+
20
+ - Khi cần màn hình nhập mã PIN hoặc mật khẩu chỉ có số.
21
+ - Các ứng dụng cần bàn phím số lớn (vd: trên máy POS, thiết bị cảm ứng).
22
+ - Tích hợp trong các module quay số (Dialer/VoIP).
23
+
24
+ ## Cài đặt
25
+
26
+ ```bash
27
+ # npm
28
+ npm install @libs-ui/components-inputs-keyboard
29
+
30
+ # yarn
31
+ yarn add @libs-ui/components-inputs-keyboard
32
+ ```
33
+
34
+ ## Import
35
+
36
+ ```typescript
37
+ import { LibsUiComponentsInputsKeyboardComponent } from '@libs-ui/components-inputs-keyboard';
38
+
39
+ @Component({
40
+ standalone: true,
41
+ imports: [LibsUiComponentsInputsKeyboardComponent],
42
+ // ...
43
+ })
44
+ export class YourComponent {}
45
+ ```
46
+
47
+ ## Ví dụ
48
+
49
+ ### Cơ bản
50
+
51
+ ```html
52
+ <libs_ui-components-inputs-keyboard (outKeyCodeSelected)="onKeySelect($event)" />
53
+ ```
54
+
55
+ ## API
56
+
57
+ ### libs_ui-components-inputs-keyboard
58
+
59
+ #### Inputs
60
+
61
+ _Component hiện tại không có inputs công khai._
62
+
63
+ #### Outputs
64
+
65
+ | Property | Type | Description |
66
+ | ---------------------- | -------- | ------------------------------------------------------------ |
67
+ | `(outKeyCodeSelected)` | `string` | Emit mã code của phím khi người dùng click hoặc nhấn phím số |
68
+
69
+ ## Tuyến bố về sự kiện (Events)
70
+
71
+ Component lắng nghe sự kiện `keyup` trên toàn bộ `document`. Khi người dùng nhấn các phím từ `0` đến `9` trên bàn phím cứng, component sẽ tự động cập nhật trạng thái hiển thị và emit event ra ngoài tương tự như khi click chuột vào phím tương ứng trên UI.
72
+
73
+ ## Công nghệ
74
+
75
+ | Technology | Version | Purpose |
76
+ | --------------- | ------- | ---------------- |
77
+ | Angular | 18+ | Framework |
78
+ | Angular Signals | - | State management |
79
+ | RxJS | 7.x | Event handling |
80
+ | OnPush | - | Change Detection |
81
+
82
+ ## Demo
83
+
84
+ ```bash
85
+ npx nx serve core-ui
86
+ ```
87
+
88
+ Truy cập: `http://localhost:4500/inputs/keyboard`
89
+
90
+ ## Unit Tests
91
+
92
+ ```bash
93
+ # Chạy tests
94
+ npx nx test components-inputs-keyboard
95
+
96
+ # Coverage
97
+ npx nx test components-inputs-keyboard --coverage
98
+ ```
99
+
100
+ ## License
101
+
102
+ MIT
package/esm2022/index.mjs CHANGED
@@ -1,2 +1,4 @@
1
+ export * from './defines/keyboard.define';
2
+ export * from './interfaces/keyboard.interface';
1
3
  export * from './keyboard.component';
2
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9saWJzLXVpL2NvbXBvbmVudHMvaW5wdXRzL2tleWJvYXJkL3NyYy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLHNCQUFzQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0ICogZnJvbSAnLi9rZXlib2FyZC5jb21wb25lbnQnO1xuIl19
4
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9saWJzLXVpL2NvbXBvbmVudHMvaW5wdXRzL2tleWJvYXJkL3NyYy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLDJCQUEyQixDQUFDO0FBQzFDLGNBQWMsaUNBQWlDLENBQUM7QUFDaEQsY0FBYyxzQkFBc0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gJy4vZGVmaW5lcy9rZXlib2FyZC5kZWZpbmUnO1xuZXhwb3J0ICogZnJvbSAnLi9pbnRlcmZhY2VzL2tleWJvYXJkLmludGVyZmFjZSc7XG5leHBvcnQgKiBmcm9tICcuL2tleWJvYXJkLmNvbXBvbmVudCc7XG4iXX0=
@@ -1,2 +1,2 @@
1
1
  export {};
2
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2V5Ym9hcmQuaW50ZXJmYWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vbGlicy11aS9jb21wb25lbnRzL2lucHV0cy9rZXlib2FyZC9zcmMvaW50ZXJmYWNlcy9rZXlib2FyZC5pbnRlcmZhY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBpbnRlcmZhY2UgSUtleUNvZGUge1xuICBjb2RlOiBzdHJpbmc7XG4gIGxhYmVsOiBzdHJpbmc7XG59XG4iXX0=
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2V5Ym9hcmQuaW50ZXJmYWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vbGlicy11aS9jb21wb25lbnRzL2lucHV0cy9rZXlib2FyZC9zcmMvaW50ZXJmYWNlcy9rZXlib2FyZC5pbnRlcmZhY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbIi8qKiBD4bqldSBow6xuaCB0aMO0bmcgdGluIG3hu5l0IHBow61tIGLhuqVtIHRyw6puIGLDoG4gcGjDrW0gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSUtleUNvZGUge1xuICAvKiogTcOjIMSR4buLbmggZGFuaCBj4bunYSBwaMOtbSAodmQ6ICcxJywgJzInLCAnKicsICcjJykgKi9cbiAgY29kZTogc3RyaW5nO1xuICAvKiogTmjDo24gaGnhu4NuIHRo4buLIGPhu6dhIHBow61tIHRyw6puIGdpYW8gZGnhu4duICovXG4gIGxhYmVsOiBzdHJpbmc7XG59XG4iXX0=
@@ -1,12 +1,19 @@
1
1
  import { Component, inject, NgZone, output, signal } from '@angular/core';
2
- import { keypadConfig } from './defines/keyboard.define';
3
2
  import { fromEvent, Subject, takeUntil } from 'rxjs';
3
+ import { keypadConfig } from './defines/keyboard.define';
4
4
  import * as i0 from "@angular/core";
5
+ /**
6
+ * Component bàn phím số (Numeric Keypad)
7
+ * Hỗ trợ nhập liệu từ chuột và phím cứng (0-9).
8
+ */
5
9
  export class LibsUiComponentsInputsKeyboardComponent {
10
+ /** Chuỗi ký tự đã nhập hiển thị trên màn hình bàn phím */
6
11
  resultSelectKey = signal('');
12
+ /** Cấu hình các phím bấm (mặc định lấy từ keypadConfig) */
7
13
  configKeyCodes = signal(keypadConfig());
8
14
  onDestroy = new Subject();
9
15
  zone = inject(NgZone);
16
+ /** Event emit khi người dùng chọn một phím (trả về mã code của phím) */
10
17
  outKeyCodeSelected = output();
11
18
  ngAfterViewInit() {
12
19
  fromEvent(document, 'keyup')
@@ -43,4 +50,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
43
50
  type: Component,
44
51
  args: [{ selector: 'libs_ui-components-inputs-keyboard', standalone: true, template: "<div class=\"libs-ui-inputs-keyboard\">\n <span class=\"libs-ui-font-h1s flex justify-center mt-[12px] h-[24px]\">{{ resultSelectKey() }}</span>\n <hr class=\"mt-[12px] mb-[20px]\" />\n <div class=\"flex w-full justify-center\">\n <div class=\"flex flex-wrap -mx-2 p-0 m-0\">\n @for (config of configKeyCodes(); track config) {\n <div class=\"w-1/3 p-0 m-0 flex justify-center !mb-[28px]\">\n <div\n class=\"libs-ui-border-general libs-ui-inputs-keyboard-item libs-ui-font-h1s\"\n (click)=\"handlerClickItem($event, config)\">\n {{ config.label }}\n </div>\n </div>\n }\n </div>\n </div>\n</div>\n", styles: [".libs-ui-inputs-keyboard{background-color:#fff;padding:8px 20px}.libs-ui-inputs-keyboard .libs-ui-inputs-keyboard-item{display:flex;align-items:center;justify-content:center;border-radius:50%;height:52px;width:52px}.libs-ui-inputs-keyboard .libs-ui-inputs-keyboard-item:hover{background-color:#4e4e4e20;cursor:pointer}\n"] }]
45
52
  }] });
46
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2V5Ym9hcmQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy11aS9jb21wb25lbnRzL2lucHV0cy9rZXlib2FyZC9zcmMva2V5Ym9hcmQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy11aS9jb21wb25lbnRzL2lucHV0cy9rZXlib2FyZC9zcmMva2V5Ym9hcmQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFpQixTQUFTLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBYSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3BHLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUV6RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxNQUFNLENBQUM7O0FBVXJELE1BQU0sT0FBTyx1Q0FBdUM7SUFDeEMsZUFBZSxHQUFHLE1BQU0sQ0FBUyxFQUFFLENBQUMsQ0FBQztJQUNyQyxjQUFjLEdBQUcsTUFBTSxDQUFrQixZQUFZLEVBQUUsQ0FBQyxDQUFDO0lBRTNELFNBQVMsR0FBRyxJQUFJLE9BQU8sRUFBUSxDQUFDO0lBQ2hDLElBQUksR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7SUFFckIsa0JBQWtCLEdBQUcsTUFBTSxFQUFVLENBQUM7SUFFL0MsZUFBZTtRQUNiLFNBQVMsQ0FBUyxRQUFRLEVBQUUsT0FBTyxDQUFDO2FBQ2pDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2FBQy9CLFNBQVMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFO1lBQ25CLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRTtnQkFDakIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUM1QixDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVTLGdCQUFnQixDQUFDLEtBQVksRUFBRSxNQUFnQjtRQUN2RCxLQUFLLEVBQUUsZUFBZSxFQUFFLENBQUM7UUFDekIsSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsZUFBZSxFQUFFLEdBQUcsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDckUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDNUMsQ0FBQztJQUVPLGFBQWEsQ0FBQyxLQUFhO1FBQ2pDLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUM7UUFFOUIsSUFBSSxDQUFDLEVBQUUsSUFBSSxPQUFPLElBQUksT0FBTyxJQUFJLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLE9BQU8sSUFBSSxPQUFPLElBQUksR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUMxRSxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLEdBQUcsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7WUFFbEYsSUFBSSxNQUFNLEVBQUUsQ0FBQztnQkFDWCxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxlQUFlLEVBQUUsR0FBRyxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztnQkFDckUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDNUMsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDdEIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUM1QixDQUFDO3dHQXpDVSx1Q0FBdUM7NEZBQXZDLHVDQUF1QyxxSkNicEQsNHFCQWlCQTs7NEZESmEsdUNBQXVDO2tCQVBuRCxTQUFTOytCQUVFLG9DQUFvQyxjQUNsQyxJQUFJIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQWZ0ZXJWaWV3SW5pdCwgQ29tcG9uZW50LCBpbmplY3QsIE5nWm9uZSwgT25EZXN0cm95LCBvdXRwdXQsIHNpZ25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsga2V5cGFkQ29uZmlnIH0gZnJvbSAnLi9kZWZpbmVzL2tleWJvYXJkLmRlZmluZSc7XG5pbXBvcnQgeyBJS2V5Q29kZSB9IGZyb20gJy4vaW50ZXJmYWNlcy9rZXlib2FyZC5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgZnJvbUV2ZW50LCBTdWJqZWN0LCB0YWtlVW50aWwgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IElFdmVudCB9IGZyb20gJ0BsaWJzLXVpL2ludGVyZmFjZXMtdHlwZXMnO1xuXG5AQ29tcG9uZW50KHtcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEBhbmd1bGFyLWVzbGludC9jb21wb25lbnQtc2VsZWN0b3JcbiAgc2VsZWN0b3I6ICdsaWJzX3VpLWNvbXBvbmVudHMtaW5wdXRzLWtleWJvYXJkJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgdGVtcGxhdGVVcmw6ICcuL2tleWJvYXJkLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmw6ICcuL2tleWJvYXJkLmNvbXBvbmVudC5zY3NzJyxcbn0pXG5leHBvcnQgY2xhc3MgTGlic1VpQ29tcG9uZW50c0lucHV0c0tleWJvYXJkQ29tcG9uZW50IGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcbiAgcHJvdGVjdGVkIHJlc3VsdFNlbGVjdEtleSA9IHNpZ25hbDxzdHJpbmc+KCcnKTtcbiAgcHJvdGVjdGVkIGNvbmZpZ0tleUNvZGVzID0gc2lnbmFsPEFycmF5PElLZXlDb2RlPj4oa2V5cGFkQ29uZmlnKCkpO1xuXG4gIHByaXZhdGUgb25EZXN0cm95ID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcbiAgcHJpdmF0ZSB6b25lID0gaW5qZWN0KE5nWm9uZSk7XG5cbiAgcmVhZG9ubHkgb3V0S2V5Q29kZVNlbGVjdGVkID0gb3V0cHV0PHN0cmluZz4oKTtcblxuICBuZ0FmdGVyVmlld0luaXQoKSB7XG4gICAgZnJvbUV2ZW50PElFdmVudD4oZG9jdW1lbnQsICdrZXl1cCcpXG4gICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5vbkRlc3Ryb3kpKVxuICAgICAgLnN1YnNjcmliZSgoZXZlbnQpID0+IHtcbiAgICAgICAgdGhpcy56b25lLnJ1bigoKSA9PiB7XG4gICAgICAgICAgdGhpcy5saXN0ZW5lcktleVVwKGV2ZW50KTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyQ2xpY2tJdGVtKGV2ZW50OiBFdmVudCwgY29uZmlnOiBJS2V5Q29kZSkge1xuICAgIGV2ZW50Py5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB0aGlzLnJlc3VsdFNlbGVjdEtleS5zZXQoYCR7dGhpcy5yZXN1bHRTZWxlY3RLZXkoKX0ke2NvbmZpZy5sYWJlbH1gKTtcbiAgICB0aGlzLm91dEtleUNvZGVTZWxlY3RlZC5lbWl0KGNvbmZpZy5jb2RlKTtcbiAgfVxuXG4gIHByaXZhdGUgbGlzdGVuZXJLZXlVcChldmVudDogSUV2ZW50KSB7XG4gICAgY29uc3Qga2V5Q29kZSA9IGV2ZW50LmtleUNvZGU7XG5cbiAgICBpZiAoKDQ4IDw9IGtleUNvZGUgJiYga2V5Q29kZSA8PSA1NykgfHwgKDk2IDw9IGtleUNvZGUgJiYga2V5Q29kZSA8PSAxMDUpKSB7XG4gICAgICBjb25zdCBjb25maWcgPSB0aGlzLmNvbmZpZ0tleUNvZGVzKCkuZmluZCgoaXRlbSkgPT4gaXRlbS5jb2RlID09PSBgJHtldmVudC5rZXl9YCk7XG5cbiAgICAgIGlmIChjb25maWcpIHtcbiAgICAgICAgdGhpcy5yZXN1bHRTZWxlY3RLZXkuc2V0KGAke3RoaXMucmVzdWx0U2VsZWN0S2V5KCl9JHtjb25maWcubGFiZWx9YCk7XG4gICAgICAgIHRoaXMub3V0S2V5Q29kZVNlbGVjdGVkLmVtaXQoY29uZmlnLmNvZGUpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMub25EZXN0cm95Lm5leHQoKTtcbiAgICB0aGlzLm9uRGVzdHJveS5jb21wbGV0ZSgpO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwibGlicy11aS1pbnB1dHMta2V5Ym9hcmRcIj5cbiAgPHNwYW4gY2xhc3M9XCJsaWJzLXVpLWZvbnQtaDFzIGZsZXgganVzdGlmeS1jZW50ZXIgbXQtWzEycHhdIGgtWzI0cHhdXCI+e3sgcmVzdWx0U2VsZWN0S2V5KCkgfX08L3NwYW4+XG4gIDxociBjbGFzcz1cIm10LVsxMnB4XSBtYi1bMjBweF1cIiAvPlxuICA8ZGl2IGNsYXNzPVwiZmxleCB3LWZ1bGwganVzdGlmeS1jZW50ZXJcIj5cbiAgICA8ZGl2IGNsYXNzPVwiZmxleCBmbGV4LXdyYXAgLW14LTIgcC0wIG0tMFwiPlxuICAgICAgQGZvciAoY29uZmlnIG9mIGNvbmZpZ0tleUNvZGVzKCk7IHRyYWNrIGNvbmZpZykge1xuICAgICAgICA8ZGl2IGNsYXNzPVwidy0xLzMgcC0wIG0tMCBmbGV4IGp1c3RpZnktY2VudGVyICFtYi1bMjhweF1cIj5cbiAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICBjbGFzcz1cImxpYnMtdWktYm9yZGVyLWdlbmVyYWwgbGlicy11aS1pbnB1dHMta2V5Ym9hcmQtaXRlbSBsaWJzLXVpLWZvbnQtaDFzXCJcbiAgICAgICAgICAgIChjbGljayk9XCJoYW5kbGVyQ2xpY2tJdGVtKCRldmVudCwgY29uZmlnKVwiPlxuICAgICAgICAgICAge3sgY29uZmlnLmxhYmVsIH19XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgfVxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19
53
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2V5Ym9hcmQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy11aS9jb21wb25lbnRzL2lucHV0cy9rZXlib2FyZC9zcmMva2V5Ym9hcmQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy11aS9jb21wb25lbnRzL2lucHV0cy9rZXlib2FyZC9zcmMva2V5Ym9hcmQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFpQixTQUFTLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBYSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRXBHLE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNyRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7O0FBR3pEOzs7R0FHRztBQVFILE1BQU0sT0FBTyx1Q0FBdUM7SUFDbEQsMERBQTBEO0lBQ2hELGVBQWUsR0FBRyxNQUFNLENBQVMsRUFBRSxDQUFDLENBQUM7SUFFL0MsMkRBQTJEO0lBQ2pELGNBQWMsR0FBRyxNQUFNLENBQWtCLFlBQVksRUFBRSxDQUFDLENBQUM7SUFFM0QsU0FBUyxHQUFHLElBQUksT0FBTyxFQUFRLENBQUM7SUFDaEMsSUFBSSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUU5Qix3RUFBd0U7SUFDL0Qsa0JBQWtCLEdBQUcsTUFBTSxFQUFVLENBQUM7SUFFL0MsZUFBZTtRQUNiLFNBQVMsQ0FBUyxRQUFRLEVBQUUsT0FBTyxDQUFDO2FBQ2pDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2FBQy9CLFNBQVMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFO1lBQ25CLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRTtnQkFDakIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUM1QixDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVTLGdCQUFnQixDQUFDLEtBQVksRUFBRSxNQUFnQjtRQUN2RCxLQUFLLEVBQUUsZUFBZSxFQUFFLENBQUM7UUFDekIsSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsZUFBZSxFQUFFLEdBQUcsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDckUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDNUMsQ0FBQztJQUVPLGFBQWEsQ0FBQyxLQUFhO1FBQ2pDLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUM7UUFFOUIsSUFBSSxDQUFDLEVBQUUsSUFBSSxPQUFPLElBQUksT0FBTyxJQUFJLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLE9BQU8sSUFBSSxPQUFPLElBQUksR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUMxRSxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLEdBQUcsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7WUFFbEYsSUFBSSxNQUFNLEVBQUUsQ0FBQztnQkFDWCxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxlQUFlLEVBQUUsR0FBRyxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztnQkFDckUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDNUMsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDdEIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUM1QixDQUFDO3dHQTdDVSx1Q0FBdUM7NEZBQXZDLHVDQUF1QyxxSkNqQnBELDRxQkFpQkE7OzRGREFhLHVDQUF1QztrQkFQbkQsU0FBUzsrQkFFRSxvQ0FBb0MsY0FDbEMsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFmdGVyVmlld0luaXQsIENvbXBvbmVudCwgaW5qZWN0LCBOZ1pvbmUsIE9uRGVzdHJveSwgb3V0cHV0LCBzaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IElFdmVudCB9IGZyb20gJ0BsaWJzLXVpL2ludGVyZmFjZXMtdHlwZXMnO1xuaW1wb3J0IHsgZnJvbUV2ZW50LCBTdWJqZWN0LCB0YWtlVW50aWwgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGtleXBhZENvbmZpZyB9IGZyb20gJy4vZGVmaW5lcy9rZXlib2FyZC5kZWZpbmUnO1xuaW1wb3J0IHsgSUtleUNvZGUgfSBmcm9tICcuL2ludGVyZmFjZXMva2V5Ym9hcmQuaW50ZXJmYWNlJztcblxuLyoqXG4gKiBDb21wb25lbnQgYsOgbiBwaMOtbSBz4buRIChOdW1lcmljIEtleXBhZClcbiAqIEjhu5cgdHLhu6Mgbmjhuq1wIGxp4buHdSB04burIGNodeG7mXQgdsOgIHBow61tIGPhu6luZyAoMC05KS5cbiAqL1xuQENvbXBvbmVudCh7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAYW5ndWxhci1lc2xpbnQvY29tcG9uZW50LXNlbGVjdG9yXG4gIHNlbGVjdG9yOiAnbGlic191aS1jb21wb25lbnRzLWlucHV0cy1rZXlib2FyZCcsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIHRlbXBsYXRlVXJsOiAnLi9rZXlib2FyZC5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsOiAnLi9rZXlib2FyZC5jb21wb25lbnQuc2NzcycsXG59KVxuZXhwb3J0IGNsYXNzIExpYnNVaUNvbXBvbmVudHNJbnB1dHNLZXlib2FyZENvbXBvbmVudCBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveSB7XG4gIC8qKiBDaHXhu5dpIGvDvSB04buxIMSRw6Mgbmjhuq1wIGhp4buDbiB0aOG7iyB0csOqbiBtw6BuIGjDrG5oIGLDoG4gcGjDrW0gKi9cbiAgcHJvdGVjdGVkIHJlc3VsdFNlbGVjdEtleSA9IHNpZ25hbDxzdHJpbmc+KCcnKTtcblxuICAvKiogQ+G6pXUgaMOsbmggY8OhYyBwaMOtbSBi4bqlbSAobeG6t2MgxJHhu4tuaCBs4bqleSB04burIGtleXBhZENvbmZpZykgKi9cbiAgcHJvdGVjdGVkIGNvbmZpZ0tleUNvZGVzID0gc2lnbmFsPEFycmF5PElLZXlDb2RlPj4oa2V5cGFkQ29uZmlnKCkpO1xuXG4gIHByaXZhdGUgb25EZXN0cm95ID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcbiAgcHJpdmF0ZSB6b25lID0gaW5qZWN0KE5nWm9uZSk7XG5cbiAgLyoqIEV2ZW50IGVtaXQga2hpIG5nxrDhu51pIGTDuW5nIGNo4buNbiBt4buZdCBwaMOtbSAodHLhuqMgduG7gSBtw6MgY29kZSBj4bunYSBwaMOtbSkgKi9cbiAgcmVhZG9ubHkgb3V0S2V5Q29kZVNlbGVjdGVkID0gb3V0cHV0PHN0cmluZz4oKTtcblxuICBuZ0FmdGVyVmlld0luaXQoKSB7XG4gICAgZnJvbUV2ZW50PElFdmVudD4oZG9jdW1lbnQsICdrZXl1cCcpXG4gICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5vbkRlc3Ryb3kpKVxuICAgICAgLnN1YnNjcmliZSgoZXZlbnQpID0+IHtcbiAgICAgICAgdGhpcy56b25lLnJ1bigoKSA9PiB7XG4gICAgICAgICAgdGhpcy5saXN0ZW5lcktleVVwKGV2ZW50KTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBoYW5kbGVyQ2xpY2tJdGVtKGV2ZW50OiBFdmVudCwgY29uZmlnOiBJS2V5Q29kZSkge1xuICAgIGV2ZW50Py5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB0aGlzLnJlc3VsdFNlbGVjdEtleS5zZXQoYCR7dGhpcy5yZXN1bHRTZWxlY3RLZXkoKX0ke2NvbmZpZy5sYWJlbH1gKTtcbiAgICB0aGlzLm91dEtleUNvZGVTZWxlY3RlZC5lbWl0KGNvbmZpZy5jb2RlKTtcbiAgfVxuXG4gIHByaXZhdGUgbGlzdGVuZXJLZXlVcChldmVudDogSUV2ZW50KSB7XG4gICAgY29uc3Qga2V5Q29kZSA9IGV2ZW50LmtleUNvZGU7XG5cbiAgICBpZiAoKDQ4IDw9IGtleUNvZGUgJiYga2V5Q29kZSA8PSA1NykgfHwgKDk2IDw9IGtleUNvZGUgJiYga2V5Q29kZSA8PSAxMDUpKSB7XG4gICAgICBjb25zdCBjb25maWcgPSB0aGlzLmNvbmZpZ0tleUNvZGVzKCkuZmluZCgoaXRlbSkgPT4gaXRlbS5jb2RlID09PSBgJHtldmVudC5rZXl9YCk7XG5cbiAgICAgIGlmIChjb25maWcpIHtcbiAgICAgICAgdGhpcy5yZXN1bHRTZWxlY3RLZXkuc2V0KGAke3RoaXMucmVzdWx0U2VsZWN0S2V5KCl9JHtjb25maWcubGFiZWx9YCk7XG4gICAgICAgIHRoaXMub3V0S2V5Q29kZVNlbGVjdGVkLmVtaXQoY29uZmlnLmNvZGUpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMub25EZXN0cm95Lm5leHQoKTtcbiAgICB0aGlzLm9uRGVzdHJveS5jb21wbGV0ZSgpO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwibGlicy11aS1pbnB1dHMta2V5Ym9hcmRcIj5cbiAgPHNwYW4gY2xhc3M9XCJsaWJzLXVpLWZvbnQtaDFzIGZsZXgganVzdGlmeS1jZW50ZXIgbXQtWzEycHhdIGgtWzI0cHhdXCI+e3sgcmVzdWx0U2VsZWN0S2V5KCkgfX08L3NwYW4+XG4gIDxociBjbGFzcz1cIm10LVsxMnB4XSBtYi1bMjBweF1cIiAvPlxuICA8ZGl2IGNsYXNzPVwiZmxleCB3LWZ1bGwganVzdGlmeS1jZW50ZXJcIj5cbiAgICA8ZGl2IGNsYXNzPVwiZmxleCBmbGV4LXdyYXAgLW14LTIgcC0wIG0tMFwiPlxuICAgICAgQGZvciAoY29uZmlnIG9mIGNvbmZpZ0tleUNvZGVzKCk7IHRyYWNrIGNvbmZpZykge1xuICAgICAgICA8ZGl2IGNsYXNzPVwidy0xLzMgcC0wIG0tMCBmbGV4IGp1c3RpZnktY2VudGVyICFtYi1bMjhweF1cIj5cbiAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICBjbGFzcz1cImxpYnMtdWktYm9yZGVyLWdlbmVyYWwgbGlicy11aS1pbnB1dHMta2V5Ym9hcmQtaXRlbSBsaWJzLXVpLWZvbnQtaDFzXCJcbiAgICAgICAgICAgIChjbGljayk9XCJoYW5kbGVyQ2xpY2tJdGVtKCRldmVudCwgY29uZmlnKVwiPlxuICAgICAgICAgICAge3sgY29uZmlnLmxhYmVsIH19XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgfVxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19
@@ -55,11 +55,18 @@ const keypadConfig = () => {
55
55
  ];
56
56
  };
57
57
 
58
+ /**
59
+ * Component bàn phím số (Numeric Keypad)
60
+ * Hỗ trợ nhập liệu từ chuột và phím cứng (0-9).
61
+ */
58
62
  class LibsUiComponentsInputsKeyboardComponent {
63
+ /** Chuỗi ký tự đã nhập hiển thị trên màn hình bàn phím */
59
64
  resultSelectKey = signal('');
65
+ /** Cấu hình các phím bấm (mặc định lấy từ keypadConfig) */
60
66
  configKeyCodes = signal(keypadConfig());
61
67
  onDestroy = new Subject();
62
68
  zone = inject(NgZone);
69
+ /** Event emit khi người dùng chọn một phím (trả về mã code của phím) */
63
70
  outKeyCodeSelected = output();
64
71
  ngAfterViewInit() {
65
72
  fromEvent(document, 'keyup')
@@ -101,5 +108,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
101
108
  * Generated bundle index. Do not edit.
102
109
  */
103
110
 
104
- export { LibsUiComponentsInputsKeyboardComponent };
111
+ export { LibsUiComponentsInputsKeyboardComponent, keypadConfig };
105
112
  //# sourceMappingURL=libs-ui-components-inputs-keyboard.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"libs-ui-components-inputs-keyboard.mjs","sources":["../../../../../../libs-ui/components/inputs/keyboard/src/defines/keyboard.define.ts","../../../../../../libs-ui/components/inputs/keyboard/src/keyboard.component.ts","../../../../../../libs-ui/components/inputs/keyboard/src/keyboard.component.html","../../../../../../libs-ui/components/inputs/keyboard/src/libs-ui-components-inputs-keyboard.ts"],"sourcesContent":["import { IKeyCode } from '../interfaces/keyboard.interface';\n\nexport const keypadConfig = (): Array<IKeyCode> => {\n return [\n {\n code: '1',\n label: '1',\n },\n {\n code: '2',\n label: '2',\n },\n {\n code: '3',\n label: '3',\n },\n {\n code: '4',\n label: '4',\n },\n {\n code: '5',\n label: '5',\n },\n {\n code: '6',\n label: '6',\n },\n {\n code: '7',\n label: '7',\n },\n {\n code: '8',\n label: '8',\n },\n {\n code: '9',\n label: '9',\n },\n {\n code: '*',\n label: '*',\n },\n {\n code: '0',\n label: '0',\n },\n {\n code: '#',\n label: '#',\n },\n ];\n};\n","import { AfterViewInit, Component, inject, NgZone, OnDestroy, output, signal } from '@angular/core';\nimport { keypadConfig } from './defines/keyboard.define';\nimport { IKeyCode } from './interfaces/keyboard.interface';\nimport { fromEvent, Subject, takeUntil } from 'rxjs';\nimport { IEvent } from '@libs-ui/interfaces-types';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-inputs-keyboard',\n standalone: true,\n templateUrl: './keyboard.component.html',\n styleUrl: './keyboard.component.scss',\n})\nexport class LibsUiComponentsInputsKeyboardComponent implements AfterViewInit, OnDestroy {\n protected resultSelectKey = signal<string>('');\n protected configKeyCodes = signal<Array<IKeyCode>>(keypadConfig());\n\n private onDestroy = new Subject<void>();\n private zone = inject(NgZone);\n\n readonly outKeyCodeSelected = output<string>();\n\n ngAfterViewInit() {\n fromEvent<IEvent>(document, 'keyup')\n .pipe(takeUntil(this.onDestroy))\n .subscribe((event) => {\n this.zone.run(() => {\n this.listenerKeyUp(event);\n });\n });\n }\n\n protected handlerClickItem(event: Event, config: IKeyCode) {\n event?.stopPropagation();\n this.resultSelectKey.set(`${this.resultSelectKey()}${config.label}`);\n this.outKeyCodeSelected.emit(config.code);\n }\n\n private listenerKeyUp(event: IEvent) {\n const keyCode = event.keyCode;\n\n if ((48 <= keyCode && keyCode <= 57) || (96 <= keyCode && keyCode <= 105)) {\n const config = this.configKeyCodes().find((item) => item.code === `${event.key}`);\n\n if (config) {\n this.resultSelectKey.set(`${this.resultSelectKey()}${config.label}`);\n this.outKeyCodeSelected.emit(config.code);\n }\n }\n }\n\n ngOnDestroy(): void {\n this.onDestroy.next();\n this.onDestroy.complete();\n }\n}\n","<div class=\"libs-ui-inputs-keyboard\">\n <span class=\"libs-ui-font-h1s flex justify-center mt-[12px] h-[24px]\">{{ resultSelectKey() }}</span>\n <hr class=\"mt-[12px] mb-[20px]\" />\n <div class=\"flex w-full justify-center\">\n <div class=\"flex flex-wrap -mx-2 p-0 m-0\">\n @for (config of configKeyCodes(); track config) {\n <div class=\"w-1/3 p-0 m-0 flex justify-center !mb-[28px]\">\n <div\n class=\"libs-ui-border-general libs-ui-inputs-keyboard-item libs-ui-font-h1s\"\n (click)=\"handlerClickItem($event, config)\">\n {{ config.label }}\n </div>\n </div>\n }\n </div>\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"libs-ui-components-inputs-keyboard.mjs","sources":["../../../../../../libs-ui/components/inputs/keyboard/src/defines/keyboard.define.ts","../../../../../../libs-ui/components/inputs/keyboard/src/keyboard.component.ts","../../../../../../libs-ui/components/inputs/keyboard/src/keyboard.component.html","../../../../../../libs-ui/components/inputs/keyboard/src/libs-ui-components-inputs-keyboard.ts"],"sourcesContent":["import { IKeyCode } from '../interfaces/keyboard.interface';\n\nexport const keypadConfig = (): Array<IKeyCode> => {\n return [\n {\n code: '1',\n label: '1',\n },\n {\n code: '2',\n label: '2',\n },\n {\n code: '3',\n label: '3',\n },\n {\n code: '4',\n label: '4',\n },\n {\n code: '5',\n label: '5',\n },\n {\n code: '6',\n label: '6',\n },\n {\n code: '7',\n label: '7',\n },\n {\n code: '8',\n label: '8',\n },\n {\n code: '9',\n label: '9',\n },\n {\n code: '*',\n label: '*',\n },\n {\n code: '0',\n label: '0',\n },\n {\n code: '#',\n label: '#',\n },\n ];\n};\n","import { AfterViewInit, Component, inject, NgZone, OnDestroy, output, signal } from '@angular/core';\nimport { IEvent } from '@libs-ui/interfaces-types';\nimport { fromEvent, Subject, takeUntil } from 'rxjs';\nimport { keypadConfig } from './defines/keyboard.define';\nimport { IKeyCode } from './interfaces/keyboard.interface';\n\n/**\n * Component bàn phím số (Numeric Keypad)\n * Hỗ trợ nhập liệu từ chuột và phím cứng (0-9).\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-inputs-keyboard',\n standalone: true,\n templateUrl: './keyboard.component.html',\n styleUrl: './keyboard.component.scss',\n})\nexport class LibsUiComponentsInputsKeyboardComponent implements AfterViewInit, OnDestroy {\n /** Chuỗi ký tự đã nhập hiển thị trên màn hình bàn phím */\n protected resultSelectKey = signal<string>('');\n\n /** Cấu hình các phím bấm (mặc định lấy từ keypadConfig) */\n protected configKeyCodes = signal<Array<IKeyCode>>(keypadConfig());\n\n private onDestroy = new Subject<void>();\n private zone = inject(NgZone);\n\n /** Event emit khi người dùng chọn một phím (trả về mã code của phím) */\n readonly outKeyCodeSelected = output<string>();\n\n ngAfterViewInit() {\n fromEvent<IEvent>(document, 'keyup')\n .pipe(takeUntil(this.onDestroy))\n .subscribe((event) => {\n this.zone.run(() => {\n this.listenerKeyUp(event);\n });\n });\n }\n\n protected handlerClickItem(event: Event, config: IKeyCode) {\n event?.stopPropagation();\n this.resultSelectKey.set(`${this.resultSelectKey()}${config.label}`);\n this.outKeyCodeSelected.emit(config.code);\n }\n\n private listenerKeyUp(event: IEvent) {\n const keyCode = event.keyCode;\n\n if ((48 <= keyCode && keyCode <= 57) || (96 <= keyCode && keyCode <= 105)) {\n const config = this.configKeyCodes().find((item) => item.code === `${event.key}`);\n\n if (config) {\n this.resultSelectKey.set(`${this.resultSelectKey()}${config.label}`);\n this.outKeyCodeSelected.emit(config.code);\n }\n }\n }\n\n ngOnDestroy(): void {\n this.onDestroy.next();\n this.onDestroy.complete();\n }\n}\n","<div class=\"libs-ui-inputs-keyboard\">\n <span class=\"libs-ui-font-h1s flex justify-center mt-[12px] h-[24px]\">{{ resultSelectKey() }}</span>\n <hr class=\"mt-[12px] mb-[20px]\" />\n <div class=\"flex w-full justify-center\">\n <div class=\"flex flex-wrap -mx-2 p-0 m-0\">\n @for (config of configKeyCodes(); track config) {\n <div class=\"w-1/3 p-0 m-0 flex justify-center !mb-[28px]\">\n <div\n class=\"libs-ui-border-general libs-ui-inputs-keyboard-item libs-ui-font-h1s\"\n (click)=\"handlerClickItem($event, config)\">\n {{ config.label }}\n </div>\n </div>\n }\n </div>\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
package/index.d.ts CHANGED
@@ -1 +1,3 @@
1
+ export * from './defines/keyboard.define';
2
+ export * from './interfaces/keyboard.interface';
1
3
  export * from './keyboard.component';
@@ -1,4 +1,7 @@
1
+ /** Cấu hình thông tin một phím bấm trên bàn phím */
1
2
  export interface IKeyCode {
3
+ /** Mã định danh của phím (vd: '1', '2', '*', '#') */
2
4
  code: string;
5
+ /** Nhãn hiển thị của phím trên giao diện */
3
6
  label: string;
4
7
  }
@@ -1,11 +1,18 @@
1
1
  import { AfterViewInit, OnDestroy } from '@angular/core';
2
2
  import { IKeyCode } from './interfaces/keyboard.interface';
3
3
  import * as i0 from "@angular/core";
4
+ /**
5
+ * Component bàn phím số (Numeric Keypad)
6
+ * Hỗ trợ nhập liệu từ chuột và phím cứng (0-9).
7
+ */
4
8
  export declare class LibsUiComponentsInputsKeyboardComponent implements AfterViewInit, OnDestroy {
9
+ /** Chuỗi ký tự đã nhập hiển thị trên màn hình bàn phím */
5
10
  protected resultSelectKey: import("@angular/core").WritableSignal<string>;
11
+ /** Cấu hình các phím bấm (mặc định lấy từ keypadConfig) */
6
12
  protected configKeyCodes: import("@angular/core").WritableSignal<IKeyCode[]>;
7
13
  private onDestroy;
8
14
  private zone;
15
+ /** Event emit khi người dùng chọn một phím (trả về mã code của phím) */
9
16
  readonly outKeyCodeSelected: import("@angular/core").OutputEmitterRef<string>;
10
17
  ngAfterViewInit(): void;
11
18
  protected handlerClickItem(event: Event, config: IKeyCode): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@libs-ui/components-inputs-keyboard",
3
- "version": "0.2.355-9",
3
+ "version": "0.2.356-0",
4
4
  "peerDependencies": {
5
5
  "@angular/common": ">=18.0.0",
6
6
  "@angular/core": ">=18.0.0"