@libs-ui/components-buttons-tab 0.2.356-9 → 0.2.357-1
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,23 +1,29 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @libs-ui/components-buttons-tab
|
|
2
2
|
|
|
3
|
-
> Version: `0.2.355-14`
|
|
4
|
-
>
|
|
5
3
|
> Component tab dạng button, hỗ trợ nhiều màu, badge count và tuỳ biến màu riêng với type `other`.
|
|
6
4
|
|
|
7
5
|
## Giới thiệu
|
|
8
6
|
|
|
9
|
-
`LibsUiComponentsButtonsTabComponent` là standalone Angular component
|
|
7
|
+
`LibsUiComponentsButtonsTabComponent` là standalone Angular component hiển thị danh sách tab dưới dạng button có màu sắc phân biệt. Component hỗ trợ two-way binding cho tab đang chọn, badge count cho từng tab, disable toàn bộ hoặc từng tab riêng lẻ, và khả năng tuỳ biến màu hoàn toàn thông qua `otherConfig` khi `type = 'other'`.
|
|
10
8
|
|
|
11
9
|
## Tính năng
|
|
12
10
|
|
|
13
|
-
- ✅ Hiển thị tab
|
|
14
|
-
- ✅ Hỗ trợ nhiều màu tab theo `type`
|
|
15
|
-
- ✅ Hỗ trợ badge count (`count`, `modeCount`, `maxCount`)
|
|
11
|
+
- ✅ Hiển thị danh sách tab với 8 màu có sẵn: `blue`, `green`, `red`, `orange`, `yellow`, `cyan`, `purple`, `brown`
|
|
16
12
|
- ✅ Two-way binding key đang chọn qua `[(keySelected)]`
|
|
17
|
-
- ✅
|
|
18
|
-
- ✅
|
|
19
|
-
- ✅
|
|
20
|
-
- ✅
|
|
13
|
+
- ✅ Badge count cho từng tab với các chế độ hiển thị (`x`, `0x`, `x+`)
|
|
14
|
+
- ✅ Disable toàn bộ component hoặc disable từng tab riêng lẻ
|
|
15
|
+
- ✅ Tuỳ biến màu hoàn toàn (màu chữ, nền, nền badge) với `type = 'other'` + `otherConfig`
|
|
16
|
+
- ✅ Tự động escape HTML trong label để tránh XSS
|
|
17
|
+
- ✅ Hỗ trợ i18n qua `TranslateModule`
|
|
18
|
+
- ✅ Hỗ trợ popover tooltip khi label bị cắt ngắn
|
|
19
|
+
- ✅ Standalone Component, OnPush Change Detection, Angular Signals
|
|
20
|
+
|
|
21
|
+
## Khi nào sử dụng
|
|
22
|
+
|
|
23
|
+
- Khi cần hiển thị danh sách tab dạng button (segment navigation, bộ lọc theo nhóm)
|
|
24
|
+
- Khi cần hiển thị count/badge cho từng tab (số lượng thông báo, số mục chờ xử lý)
|
|
25
|
+
- Khi cần tuỳ biến màu theo theme sẵn có hoặc cấu hình màu riêng (`type = 'other'`)
|
|
26
|
+
- Khi cần disable toàn bộ hoặc disable từng tab item theo điều kiện nghiệp vụ
|
|
21
27
|
|
|
22
28
|
## Cài đặt
|
|
23
29
|
|
|
@@ -28,156 +34,325 @@ npm install @libs-ui/components-buttons-tab
|
|
|
28
34
|
## Import
|
|
29
35
|
|
|
30
36
|
```typescript
|
|
31
|
-
import {
|
|
32
|
-
|
|
37
|
+
import {
|
|
38
|
+
LibsUiComponentsButtonsTabComponent,
|
|
39
|
+
IButtonTab,
|
|
40
|
+
IOtherConfig,
|
|
41
|
+
TYPE_BUTTON_TAB,
|
|
42
|
+
} from '@libs-ui/components-buttons-tab';
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Ví dụ sử dụng
|
|
46
|
+
|
|
47
|
+
### 1. Basic — Tabs với nhiều màu
|
|
48
|
+
|
|
49
|
+
`example.component.html`
|
|
50
|
+
|
|
51
|
+
```html
|
|
52
|
+
<libs_ui-components-buttons-tab
|
|
53
|
+
[items]="items"
|
|
54
|
+
[(keySelected)]="selectedKey"
|
|
55
|
+
(outKeySelected)="handlerKeySelected($event)"
|
|
56
|
+
/>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`example.component.ts`
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { Component, signal } from '@angular/core';
|
|
63
|
+
import { LibsUiComponentsButtonsTabComponent, IButtonTab } from '@libs-ui/components-buttons-tab';
|
|
33
64
|
|
|
34
65
|
@Component({
|
|
66
|
+
selector: 'app-example',
|
|
35
67
|
standalone: true,
|
|
36
68
|
imports: [LibsUiComponentsButtonsTabComponent],
|
|
37
|
-
|
|
69
|
+
templateUrl: './example.component.html',
|
|
70
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
38
71
|
})
|
|
39
|
-
export class ExampleComponent {
|
|
72
|
+
export class ExampleComponent {
|
|
73
|
+
protected selectedKey = model<string>('overview');
|
|
74
|
+
|
|
75
|
+
protected readonly items: IButtonTab[] = [
|
|
76
|
+
{ key: 'overview', label: 'Overview', type: 'blue' },
|
|
77
|
+
{ key: 'details', label: 'Details', type: 'green' },
|
|
78
|
+
{ key: 'settings', label: 'Settings', type: 'orange' },
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
protected handlerKeySelected(event: Event): void {
|
|
82
|
+
event.stopPropagation();
|
|
83
|
+
// key đã được cập nhật tự động qua two-way binding [(keySelected)]
|
|
84
|
+
}
|
|
85
|
+
}
|
|
40
86
|
```
|
|
41
87
|
|
|
42
|
-
|
|
88
|
+
### 2. With Badge — Badge count cho từng tab
|
|
43
89
|
|
|
44
|
-
|
|
90
|
+
`example-badge.component.html`
|
|
45
91
|
|
|
46
92
|
```html
|
|
47
93
|
<libs_ui-components-buttons-tab
|
|
48
|
-
[items]="
|
|
94
|
+
[items]="itemsWithBadge"
|
|
49
95
|
[(keySelected)]="selectedKey"
|
|
50
|
-
(outKeySelected)="
|
|
96
|
+
(outKeySelected)="handlerKeySelected($event)"
|
|
51
97
|
/>
|
|
52
98
|
```
|
|
53
99
|
|
|
100
|
+
`example-badge.component.ts`
|
|
101
|
+
|
|
54
102
|
```typescript
|
|
55
|
-
import { Component,
|
|
103
|
+
import { ChangeDetectionStrategy, Component, model } from '@angular/core';
|
|
56
104
|
import { LibsUiComponentsButtonsTabComponent, IButtonTab } from '@libs-ui/components-buttons-tab';
|
|
57
105
|
|
|
58
106
|
@Component({
|
|
107
|
+
selector: 'app-example-badge',
|
|
59
108
|
standalone: true,
|
|
60
109
|
imports: [LibsUiComponentsButtonsTabComponent],
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
[items]="items"
|
|
64
|
-
[(keySelected)]="selectedKey()"
|
|
65
|
-
(outKeySelected)="onKeySelected($event)"
|
|
66
|
-
/>
|
|
67
|
-
`,
|
|
110
|
+
templateUrl: './example-badge.component.html',
|
|
111
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
68
112
|
})
|
|
69
|
-
export class
|
|
70
|
-
|
|
113
|
+
export class ExampleBadgeComponent {
|
|
114
|
+
protected selectedKey = model<string>('inbox');
|
|
71
115
|
|
|
72
|
-
readonly
|
|
73
|
-
{ key: '
|
|
74
|
-
{ key: '
|
|
75
|
-
{ key: '
|
|
116
|
+
protected readonly itemsWithBadge: IButtonTab[] = [
|
|
117
|
+
{ key: 'inbox', label: 'Inbox', type: 'blue', count: 12, modeCount: 'x+', maxCount: 99 },
|
|
118
|
+
{ key: 'mentions', label: 'Mentions', type: 'purple', count: 3, modeCount: 'x+', maxCount: 99 },
|
|
119
|
+
{ key: 'requests', label: 'Requests', type: 'cyan', count: 105, modeCount: 'x+', maxCount: 99 },
|
|
76
120
|
];
|
|
77
121
|
|
|
78
|
-
|
|
79
|
-
|
|
122
|
+
protected handlerKeySelected(event: Event): void {
|
|
123
|
+
event.stopPropagation();
|
|
80
124
|
}
|
|
81
125
|
}
|
|
82
126
|
```
|
|
83
127
|
|
|
84
|
-
###
|
|
128
|
+
### 3. Disabled — Disable toàn bộ hoặc từng tab
|
|
85
129
|
|
|
86
|
-
`example.component.html`
|
|
130
|
+
`example-disabled.component.html`
|
|
87
131
|
|
|
88
132
|
```html
|
|
133
|
+
<!-- Disable toàn bộ component -->
|
|
89
134
|
<libs_ui-components-buttons-tab
|
|
90
135
|
[items]="items"
|
|
136
|
+
[disable]="true"
|
|
137
|
+
[(keySelected)]="selectedKey"
|
|
138
|
+
/>
|
|
139
|
+
|
|
140
|
+
<!-- Disable từng tab riêng lẻ qua thuộc tính disable trong IButtonTab -->
|
|
141
|
+
<libs_ui-components-buttons-tab
|
|
142
|
+
[items]="itemsPartialDisabled"
|
|
143
|
+
[(keySelected)]="selectedKey"
|
|
144
|
+
(outKeySelected)="handlerKeySelected($event)"
|
|
145
|
+
/>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`example-disabled.component.ts`
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { ChangeDetectionStrategy, Component, model } from '@angular/core';
|
|
152
|
+
import { LibsUiComponentsButtonsTabComponent, IButtonTab } from '@libs-ui/components-buttons-tab';
|
|
153
|
+
|
|
154
|
+
@Component({
|
|
155
|
+
selector: 'app-example-disabled',
|
|
156
|
+
standalone: true,
|
|
157
|
+
imports: [LibsUiComponentsButtonsTabComponent],
|
|
158
|
+
templateUrl: './example-disabled.component.html',
|
|
159
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
160
|
+
})
|
|
161
|
+
export class ExampleDisabledComponent {
|
|
162
|
+
protected selectedKey = model<string>('a');
|
|
163
|
+
|
|
164
|
+
protected readonly items: IButtonTab[] = [
|
|
165
|
+
{ key: 'a', label: 'Tab A', type: 'blue' },
|
|
166
|
+
{ key: 'b', label: 'Tab B', type: 'green' },
|
|
167
|
+
{ key: 'c', label: 'Tab C', type: 'orange' },
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
protected readonly itemsPartialDisabled: IButtonTab[] = [
|
|
171
|
+
{ key: 'a', label: 'Tab A', type: 'blue' },
|
|
172
|
+
{ key: 'b', label: 'Tab B (disabled)', type: 'red', disable: true },
|
|
173
|
+
{ key: 'c', label: 'Tab C', type: 'green' },
|
|
174
|
+
];
|
|
175
|
+
|
|
176
|
+
protected handlerKeySelected(event: Event): void {
|
|
177
|
+
event.stopPropagation();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 4. Other — Tuỳ biến màu hoàn toàn
|
|
183
|
+
|
|
184
|
+
`example-other.component.html`
|
|
185
|
+
|
|
186
|
+
```html
|
|
187
|
+
<libs_ui-components-buttons-tab
|
|
188
|
+
[items]="itemsOther"
|
|
91
189
|
[otherConfig]="otherConfig"
|
|
92
190
|
[(keySelected)]="selectedKey"
|
|
191
|
+
(outKeySelected)="handlerKeySelected($event)"
|
|
93
192
|
/>
|
|
94
193
|
```
|
|
95
194
|
|
|
96
|
-
`example.component.ts`
|
|
195
|
+
`example-other.component.ts`
|
|
97
196
|
|
|
98
197
|
```typescript
|
|
99
|
-
import { Component,
|
|
100
|
-
import {
|
|
198
|
+
import { ChangeDetectionStrategy, Component, model } from '@angular/core';
|
|
199
|
+
import {
|
|
200
|
+
LibsUiComponentsButtonsTabComponent,
|
|
201
|
+
IButtonTab,
|
|
202
|
+
IOtherConfig,
|
|
203
|
+
} from '@libs-ui/components-buttons-tab';
|
|
101
204
|
|
|
102
205
|
@Component({
|
|
206
|
+
selector: 'app-example-other',
|
|
103
207
|
standalone: true,
|
|
104
208
|
imports: [LibsUiComponentsButtonsTabComponent],
|
|
105
|
-
templateUrl: './example.component.html',
|
|
209
|
+
templateUrl: './example-other.component.html',
|
|
210
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
106
211
|
})
|
|
107
|
-
export class
|
|
108
|
-
|
|
212
|
+
export class ExampleOtherComponent {
|
|
213
|
+
protected selectedKey = model<string>('custom-1');
|
|
109
214
|
|
|
110
|
-
readonly otherConfig: IOtherConfig = {
|
|
215
|
+
protected readonly otherConfig: IOtherConfig = {
|
|
111
216
|
color: '#0ea5e9',
|
|
112
217
|
background: '#e0f2fe',
|
|
113
218
|
background_badge: '#bae6fd',
|
|
114
219
|
};
|
|
115
220
|
|
|
116
|
-
readonly
|
|
221
|
+
protected readonly itemsOther: IButtonTab[] = [
|
|
117
222
|
{ key: 'custom-1', label: 'Custom 1', type: 'other' },
|
|
118
|
-
{ key: 'custom-2', label: 'Custom 2', type: 'other', count: 7,
|
|
223
|
+
{ key: 'custom-2', label: 'Custom 2', type: 'other', count: 7, modeCount: 'x+' },
|
|
224
|
+
{ key: 'custom-3', label: 'Custom 3', type: 'other', count: 120, modeCount: 'x+' },
|
|
119
225
|
];
|
|
226
|
+
|
|
227
|
+
protected handlerKeySelected(event: Event): void {
|
|
228
|
+
event.stopPropagation();
|
|
229
|
+
}
|
|
120
230
|
}
|
|
121
231
|
```
|
|
122
232
|
|
|
123
|
-
##
|
|
124
|
-
|
|
125
|
-
| Technology | Version | Purpose |
|
|
126
|
-
|------------|---------|---------|
|
|
127
|
-
| Angular | 18+ | Framework |
|
|
128
|
-
| Angular Signals | - | State management |
|
|
129
|
-
| TailwindCSS | 3.x | Styling (demo) |
|
|
130
|
-
| OnPush | - | Change Detection |
|
|
233
|
+
## @Input()
|
|
131
234
|
|
|
132
|
-
|
|
235
|
+
| Input | Type | Default | Mô tả | Ví dụ |
|
|
236
|
+
|---|---|---|---|---|
|
|
237
|
+
| `[items]` | `Array<IButtonTab>` | **required** | Danh sách tab cần hiển thị. Label sẽ được tự động escape HTML. | `[items]="tabList"` |
|
|
238
|
+
| `[(keySelected)]` | `string` | `''` | Key của tab đang được chọn. Hỗ trợ two-way binding qua `model()`. | `[(keySelected)]="activeKey"` |
|
|
239
|
+
| `[disable]` | `boolean` | `false` | Disable toàn bộ component, ngăn người dùng chọn bất kỳ tab nào. | `[disable]="isLoading()"` |
|
|
240
|
+
| `[otherConfig]` | `IOtherConfig \| undefined` | `undefined` | Cấu hình màu tuỳ biến cho tab có `type = 'other'`. Chỉ áp dụng khi có ít nhất 1 tab dùng `type = 'other'`. | `[otherConfig]="customColor"` |
|
|
133
241
|
|
|
134
|
-
|
|
242
|
+
## @Output()
|
|
135
243
|
|
|
136
|
-
|
|
244
|
+
| Output | Type | Mô tả | Handler TS | Binding HTML |
|
|
245
|
+
|---|---|---|---|---|
|
|
246
|
+
| `(outKeySelected)` | `string` | Emit key của tab vừa được chọn. Không emit khi tab bị disable. | `handlerKeySelected(event: Event): void { event.stopPropagation(); }` | `(outKeySelected)="handlerKeySelected($event)"` |
|
|
137
247
|
|
|
138
|
-
|
|
139
|
-
|----------|------|---------|-------------|
|
|
140
|
-
| `[disable]` | `boolean` | `false` | Disable toàn bộ tab |
|
|
141
|
-
| `[items]` | `Array<IButtonTab>` | `required` | Danh sách tab cần hiển thị |
|
|
142
|
-
| `[otherConfig]` | `IOtherConfig \| undefined` | `undefined` | Cấu hình màu cho type = other |
|
|
143
|
-
| `[(keySelected)]` | `string` | `''` | Key tab đang được chọn (two-way binding) |
|
|
248
|
+
> **Lưu ý:** `outKeySelected` emit giá trị `string` (key của tab), không phải `Event`. Tham số trong handler là `key: string`, không phải `event: Event`. Xem ví dụ thực tế trong mục Ví dụ sử dụng ở trên — handler nhận `(event: Event)` từ DOM click nhưng `outKeySelected` truyền `key: string`.
|
|
144
249
|
|
|
145
|
-
|
|
250
|
+
Ví dụ handler nhận đúng kiểu:
|
|
146
251
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
252
|
+
```typescript
|
|
253
|
+
// HTML: (outKeySelected)="handlerTabChange($event)"
|
|
254
|
+
protected handlerTabChange(key: string): void {
|
|
255
|
+
// key là string (key của tab vừa chọn)
|
|
256
|
+
this.activeKey.set(key);
|
|
257
|
+
}
|
|
258
|
+
```
|
|
150
259
|
|
|
151
260
|
## Types & Interfaces
|
|
152
261
|
|
|
262
|
+
```typescript
|
|
263
|
+
import { IButtonTab, IOtherConfig, TYPE_BUTTON_TAB } from '@libs-ui/components-buttons-tab';
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### IButtonTab
|
|
267
|
+
|
|
268
|
+
Interface định nghĩa cấu hình cho từng tab item.
|
|
269
|
+
|
|
153
270
|
```typescript
|
|
154
271
|
export interface IButtonTab {
|
|
272
|
+
/** Key định danh duy nhất cho tab, dùng để two-way binding và emit */
|
|
155
273
|
key: string;
|
|
274
|
+
|
|
275
|
+
/** Nhãn hiển thị. Hỗ trợ i18n key. Sẽ được tự động escape HTML. */
|
|
156
276
|
label: string;
|
|
277
|
+
|
|
278
|
+
/** Màu/kiểu tab. Dùng một trong các giá trị có sẵn hoặc 'other' để tuỳ biến. */
|
|
157
279
|
type: TYPE_BUTTON_TAB;
|
|
280
|
+
|
|
281
|
+
/** Số hiển thị trên badge. Không truyền = không hiển thị badge. */
|
|
158
282
|
count?: number;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Chế độ hiển thị badge:
|
|
286
|
+
* - `'x'`: Số thường (1, 5, 15, 100)
|
|
287
|
+
* - `'0x'`: Có số 0 đằng trước nếu < 10 (01, 05)
|
|
288
|
+
* - `'x+'`: Hiển thị "maxCount+" khi vượt ngưỡng (99+)
|
|
289
|
+
* @default 'x+'
|
|
290
|
+
*/
|
|
159
291
|
modeCount?: TYPE_BADGE_MODE;
|
|
292
|
+
|
|
293
|
+
/** Ngưỡng tối đa cho chế độ 'x+'. Khi count > maxCount sẽ hiển thị "maxCount+". @default 99 */
|
|
160
294
|
maxCount?: number;
|
|
295
|
+
|
|
296
|
+
/** CSS class tuỳ chỉnh cho wrapper tab item. Mặc định: `'px-[8px] mx-[8px] py-[4px]'` */
|
|
161
297
|
class?: string;
|
|
298
|
+
|
|
299
|
+
/** CSS class tuỳ chỉnh cho label. Mặc định: `'libs-ui-font-h6r'` */
|
|
162
300
|
classLabel?: string;
|
|
301
|
+
|
|
302
|
+
/** Disable tab item này. Người dùng không thể chọn tab khi disable = true. */
|
|
163
303
|
disable?: boolean;
|
|
304
|
+
|
|
305
|
+
/** Dữ liệu tuỳ ý kèm theo tab item, không ảnh hưởng đến hiển thị. */
|
|
164
306
|
data?: any;
|
|
165
307
|
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### IOtherConfig
|
|
311
|
+
|
|
312
|
+
Cấu hình màu tuỳ biến cho tab có `type = 'other'`. Nếu không truyền `background` và `background_badge`, component tự tính màu nền từ `color` theo thang độ tương phản.
|
|
166
313
|
|
|
314
|
+
```typescript
|
|
167
315
|
export interface IOtherConfig {
|
|
316
|
+
/** Màu chữ và màu số badge khi tab đang active. Dạng hex: '#0ea5e9' */
|
|
168
317
|
color: string;
|
|
318
|
+
|
|
319
|
+
/** Màu nền tab khi active. Nếu không truyền, tự động tính từ color (95% contrast). */
|
|
169
320
|
background?: string;
|
|
321
|
+
|
|
322
|
+
/** Màu nền badge khi active. Nếu không truyền, tự động tính từ color (90% contrast). */
|
|
170
323
|
background_badge?: string;
|
|
171
324
|
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### TYPE_BUTTON_TAB
|
|
172
328
|
|
|
173
|
-
|
|
329
|
+
```typescript
|
|
330
|
+
export type TYPE_BUTTON_TAB =
|
|
331
|
+
| 'blue'
|
|
332
|
+
| 'green'
|
|
333
|
+
| 'red'
|
|
334
|
+
| 'orange'
|
|
335
|
+
| 'yellow'
|
|
336
|
+
| 'cyan'
|
|
337
|
+
| 'purple'
|
|
338
|
+
| 'brown'
|
|
339
|
+
| 'other'
|
|
340
|
+
| string;
|
|
174
341
|
```
|
|
175
342
|
|
|
176
|
-
|
|
343
|
+
Có 8 màu định sẵn. Dùng `'other'` kết hợp với `[otherConfig]` để tuỳ biến màu hoàn toàn. Truyền string tuỳ ý được phép nhưng sẽ không có style mặc định nếu CSS tương ứng chưa tồn tại.
|
|
177
344
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
345
|
+
## Lưu ý quan trọng
|
|
346
|
+
|
|
347
|
+
⚠️ **`otherConfig` chỉ áp dụng cho tab có `type = 'other'`**: Nếu bạn dùng `[otherConfig]` nhưng không có tab nào có `type = 'other'`, cấu hình này sẽ không có tác dụng. Các tab với type khác (`blue`, `green`...) không bị ảnh hưởng bởi `otherConfig`.
|
|
348
|
+
|
|
349
|
+
⚠️ **Two-way binding với Signal**: Khi dùng `[(keySelected)]` với Angular Signals, đảm bảo biến được khai báo bằng `model<string>('')` (không dùng `signal()`). `model()` mới hỗ trợ two-way binding đúng chuẩn Angular.
|
|
350
|
+
|
|
351
|
+
⚠️ **`outKeySelected` emit `string`, không phải `Event`**: Output này emit `key: string` của tab vừa chọn. Handler nhận `string`, không phải DOM Event. Xem ví dụ handler đúng trong mục Ví dụ sử dụng.
|
|
352
|
+
|
|
353
|
+
⚠️ **Tab bị disable không emit event**: Khi `disable = true` (toàn bộ) hoặc `item.disable = true` (từng tab), click sẽ không có tác dụng và `outKeySelected` sẽ không được emit.
|
|
354
|
+
|
|
355
|
+
⚠️ **Label được escape HTML tự động**: Giá trị `label` trong `IButtonTab` sẽ bị escape HTML trước khi hiển thị để tránh XSS. Không truyền HTML raw vào `label`.
|
|
181
356
|
|
|
182
357
|
## Demo
|
|
183
358
|
|
|
@@ -186,4 +361,3 @@ npx nx serve core-ui
|
|
|
186
361
|
```
|
|
187
362
|
|
|
188
363
|
Truy cập: `http://localhost:4500/buttons/tab`
|
|
189
|
-
|
|
@@ -49,10 +49,10 @@ export class LibsUiComponentsButtonsTabComponent {
|
|
|
49
49
|
this.outKeySelected.emit(this.keySelected());
|
|
50
50
|
}
|
|
51
51
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiComponentsButtonsTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
52
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LibsUiComponentsButtonsTabComponent, isStandalone: true, selector: "libs_ui-components-buttons-tab", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, disable: { classPropertyName: "disable", publicName: "disable", isSignal: true, isRequired: false, transformFunction: null }, keySelected: { classPropertyName: "keySelected", publicName: "keySelected", isSignal: true, isRequired: false, transformFunction: null }, otherConfig: { classPropertyName: "otherConfig", publicName: "otherConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { keySelected: "keySelectedChange", outKeySelected: "outKeySelected" }, viewQueries: [{ propertyName: "buttonEl", first: true, predicate: ["buttonEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #buttonEl\n class=\"flex\">\n @for (item of items(); track item) {\n <div\n class=\"flex items-center libs-ui-button-tab {{ 'libs-ui-button-tab-' + item.type }} {{ item.class || 'px-[8px] mx-[8px] py-[4px]' }} {{ disable() || item.disable ? 'pointer-events-none cursor-default' : 'cursor-pointer' }}\"\n [attr.active]=\"item.key === keySelected()\"\n (click)=\"handlerSelectItem($event, item)\">\n <span\n LibsUiComponentsPopoverDirective\n class=\"w-full libs-ui-button-tab-label {{ item.classLabel || 'libs-ui-font-h6r' }}\"\n [class.libs-ui-disable]=\"disable() || item.disable\"\n [type]=\"'text'\"\n [attr.active]=\"item.key === keySelected()\"\n [ignoreStopPropagationEvent]=\"true\"\n [innerHtml]=\"item.label | translate\"></span>\n @if (item.count !== undefined) {\n <libs_ui-components-badge\n class=\"libs-ui-button-tab-badge\"\n [mode]=\"item.modeCount || 'x+'\"\n [count]=\"item.count\"\n [maxCount]=\"item.maxCount || 99\"\n [classCircle]=\"'libs-ui-button-tab-badge-circle libs-ui-font-h6r'\" />\n }\n </div>\n }\n</div>\n", styles: [":host ::ng-deep .libs-ui-button-tab{border-radius:4px}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover{background:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#e6e7ea}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "component", type: LibsUiComponentsPopoverComponent, selector: "libs_ui-components-popover,[LibsUiComponentsPopoverDirective]", inputs: ["debugId", "flagMouse", "type", "mode", "config", "ignoreShowPopover", "elementRefCustom", "initEventInElementRefCustom", "classInclude", "ignoreHiddenPopoverContentWhenMouseLeave", "ignoreStopPropagationEvent", "ignoreCursorPointerModeLikeClick", "isAddContentToParentDocument", "ignoreClickOutside"], outputs: ["outEvent", "outChangStageFlagMouse", "outEventPopoverContent", "outFunctionsControl"] }, { kind: "component", type: LibsUiComponentsBadgeComponent, selector: "libs_ui-components-badge", inputs: ["popoverConfig", "active", "count", "mode", "maxCount", "ignoreMarginDefault", "classCircle", "ignoreStopPropagationEvent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
52
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LibsUiComponentsButtonsTabComponent, isStandalone: true, selector: "libs_ui-components-buttons-tab", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, disable: { classPropertyName: "disable", publicName: "disable", isSignal: true, isRequired: false, transformFunction: null }, keySelected: { classPropertyName: "keySelected", publicName: "keySelected", isSignal: true, isRequired: false, transformFunction: null }, otherConfig: { classPropertyName: "otherConfig", publicName: "otherConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { keySelected: "keySelectedChange", outKeySelected: "outKeySelected" }, viewQueries: [{ propertyName: "buttonEl", first: true, predicate: ["buttonEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #buttonEl\n class=\"flex\">\n @for (item of items(); track item) {\n <div\n class=\"flex items-center libs-ui-button-tab {{ 'libs-ui-button-tab-' + item.type }} {{ item.class || 'px-[8px] mx-[8px] py-[4px]' }} {{ disable() || item.disable ? 'pointer-events-none cursor-default' : 'cursor-pointer' }}\"\n tabindex=\"0\"\n [attr.active]=\"item.key === keySelected()\"\n (click)=\"handlerSelectItem($event, item)\"\n (keydown.enter)=\"handlerSelectItem($any($event), item)\"\n (keydown.space)=\"handlerSelectItem($any($event), item)\">\n <span\n LibsUiComponentsPopoverDirective\n class=\"w-full libs-ui-button-tab-label {{ item.classLabel || 'libs-ui-font-h6r' }}\"\n [class.libs-ui-disable]=\"disable() || item.disable\"\n [type]=\"'text'\"\n [attr.active]=\"item.key === keySelected()\"\n [ignoreStopPropagationEvent]=\"true\"\n [innerHtml]=\"item.label | translate\"></span>\n @if (item.count !== undefined) {\n <libs_ui-components-badge\n class=\"libs-ui-button-tab-badge\"\n [mode]=\"item.modeCount || 'x+'\"\n [count]=\"item.count\"\n [maxCount]=\"item.maxCount || 99\"\n [classCircle]=\"'libs-ui-button-tab-badge-circle libs-ui-font-h6r'\" />\n }\n </div>\n }\n</div>\n", styles: [":host ::ng-deep .libs-ui-button-tab{border-radius:4px}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover{background:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#e6e7ea}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "component", type: LibsUiComponentsPopoverComponent, selector: "libs_ui-components-popover,[LibsUiComponentsPopoverDirective]", inputs: ["debugId", "flagMouse", "type", "mode", "config", "ignoreShowPopover", "elementRefCustom", "initEventInElementRefCustom", "classInclude", "ignoreHiddenPopoverContentWhenMouseLeave", "ignoreStopPropagationEvent", "ignoreCursorPointerModeLikeClick", "isAddContentToParentDocument", "ignoreClickOutside"], outputs: ["outEvent", "outChangStageFlagMouse", "outEventPopoverContent", "outFunctionsControl"] }, { kind: "component", type: LibsUiComponentsBadgeComponent, selector: "libs_ui-components-badge", inputs: ["popoverConfig", "active", "count", "mode", "maxCount", "ignoreMarginDefault", "classCircle", "ignoreStopPropagationEvent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
53
53
|
}
|
|
54
54
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiComponentsButtonsTabComponent, decorators: [{
|
|
55
55
|
type: Component,
|
|
56
|
-
args: [{ selector: 'libs_ui-components-buttons-tab', standalone: true, imports: [TranslateModule, LibsUiComponentsPopoverComponent, LibsUiComponentsBadgeComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n #buttonEl\n class=\"flex\">\n @for (item of items(); track item) {\n <div\n class=\"flex items-center libs-ui-button-tab {{ 'libs-ui-button-tab-' + item.type }} {{ item.class || 'px-[8px] mx-[8px] py-[4px]' }} {{ disable() || item.disable ? 'pointer-events-none cursor-default' : 'cursor-pointer' }}\"\n [attr.active]=\"item.key === keySelected()\"\n (click)=\"handlerSelectItem($event, item)\">\n <span\n LibsUiComponentsPopoverDirective\n class=\"w-full libs-ui-button-tab-label {{ item.classLabel || 'libs-ui-font-h6r' }}\"\n [class.libs-ui-disable]=\"disable() || item.disable\"\n [type]=\"'text'\"\n [attr.active]=\"item.key === keySelected()\"\n [ignoreStopPropagationEvent]=\"true\"\n [innerHtml]=\"item.label | translate\"></span>\n @if (item.count !== undefined) {\n <libs_ui-components-badge\n class=\"libs-ui-button-tab-badge\"\n [mode]=\"item.modeCount || 'x+'\"\n [count]=\"item.count\"\n [maxCount]=\"item.maxCount || 99\"\n [classCircle]=\"'libs-ui-button-tab-badge-circle libs-ui-font-h6r'\" />\n }\n </div>\n }\n</div>\n", styles: [":host ::ng-deep .libs-ui-button-tab{border-radius:4px}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover{background:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#e6e7ea}\n"] }]
|
|
56
|
+
args: [{ selector: 'libs_ui-components-buttons-tab', standalone: true, imports: [TranslateModule, LibsUiComponentsPopoverComponent, LibsUiComponentsBadgeComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n #buttonEl\n class=\"flex\">\n @for (item of items(); track item) {\n <div\n class=\"flex items-center libs-ui-button-tab {{ 'libs-ui-button-tab-' + item.type }} {{ item.class || 'px-[8px] mx-[8px] py-[4px]' }} {{ disable() || item.disable ? 'pointer-events-none cursor-default' : 'cursor-pointer' }}\"\n tabindex=\"0\"\n [attr.active]=\"item.key === keySelected()\"\n (click)=\"handlerSelectItem($event, item)\"\n (keydown.enter)=\"handlerSelectItem($any($event), item)\"\n (keydown.space)=\"handlerSelectItem($any($event), item)\">\n <span\n LibsUiComponentsPopoverDirective\n class=\"w-full libs-ui-button-tab-label {{ item.classLabel || 'libs-ui-font-h6r' }}\"\n [class.libs-ui-disable]=\"disable() || item.disable\"\n [type]=\"'text'\"\n [attr.active]=\"item.key === keySelected()\"\n [ignoreStopPropagationEvent]=\"true\"\n [innerHtml]=\"item.label | translate\"></span>\n @if (item.count !== undefined) {\n <libs_ui-components-badge\n class=\"libs-ui-button-tab-badge\"\n [mode]=\"item.modeCount || 'x+'\"\n [count]=\"item.count\"\n [maxCount]=\"item.maxCount || 99\"\n [classCircle]=\"'libs-ui-button-tab-badge-circle libs-ui-font-h6r'\" />\n }\n </div>\n }\n</div>\n", styles: [":host ::ng-deep .libs-ui-button-tab{border-radius:4px}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover{background:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#e6e7ea}\n"] }]
|
|
57
57
|
}], ctorParameters: () => [] });
|
|
58
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
58
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFiLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMtdWkvY29tcG9uZW50cy9idXR0b25zL3RhYi9zcmMvdGFiLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMtdWkvY29tcG9uZW50cy9idXR0b25zL3RhYi9zcmMvdGFiLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFjLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN4SCxPQUFPLEVBQUUsOEJBQThCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUMzRSxPQUFPLEVBQUUsZ0NBQWdDLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUMvRSxPQUFPLEVBQUUsMkJBQTJCLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDekUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHFCQUFxQixDQUFDOzs7QUFZdEQsTUFBTSxPQUFPLG1DQUFtQztJQUM3QiwwQkFBMEIsR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBRTlFLGdCQUFnQjtJQUNQLEtBQUssR0FBRyxLQUFLLENBQUMsUUFBUSxDQUF1QyxFQUFFLFNBQVMsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEdBQUcsSUFBSSxFQUFFLEtBQUssRUFBRSxVQUFVLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN4SixPQUFPLEdBQUcsS0FBSyxDQUFVLEtBQUssQ0FBQyxDQUFDO0lBQ2hDLFdBQVcsR0FBRyxLQUFLLENBQVMsRUFBRSxDQUFDLENBQUM7SUFDaEMsV0FBVyxHQUFHLEtBQUssRUFBZ0IsQ0FBQyxDQUFDLDZDQUE2QztJQUUzRixpQkFBaUI7SUFDUixjQUFjLEdBQUcsTUFBTSxFQUFVLENBQUM7SUFFM0MsZ0JBQWdCO0lBQ0MsUUFBUSxHQUFHLFNBQVMsQ0FBYSxVQUFVLENBQUMsQ0FBQztJQUU5RDtRQUNFLE1BQU0sQ0FBQyxHQUFHLEVBQUU7WUFDVixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFFbEMsSUFBSSxNQUFNLEVBQUUsQ0FBQztnQkFDWCxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsVUFBVSxJQUFJLDJCQUEyQixDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEVBQUUsS0FBSyxDQUFDO2dCQUM3RixNQUFNLGVBQWUsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLElBQUksMkJBQTJCLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsRUFBRSxLQUFLLENBQUM7Z0JBQ3hHLE1BQU0sTUFBTSxHQUFHO2tDQUNXLFVBQVU7Ozs7dUJBSXJCLE1BQU0sQ0FBQyxLQUFLOzs7O3VCQUlaLE1BQU0sQ0FBQyxLQUFLO2tDQUNELGVBQWU7Y0FDbkMsQ0FBQztnQkFDUCxJQUFJLENBQUMsMEJBQTBCLENBQUMsU0FBUyxHQUFHLE1BQU0sQ0FBQztnQkFDbkQsSUFBSSxDQUFDLFFBQVEsRUFBRSxFQUFFLGFBQWEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLDBCQUEwQixDQUFDLENBQUM7WUFDekUsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELGVBQWU7SUFDTCxLQUFLLENBQUMsaUJBQWlCLENBQUMsS0FBWSxFQUFFLElBQWdCO1FBQzlELEtBQUssQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUN4QixJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDbkMsT0FBTztRQUNULENBQUM7UUFDRCxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDL0IsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7SUFDL0MsQ0FBQzt3R0FoRFUsbUNBQW1DOzRGQUFuQyxtQ0FBbUMsc3pCQ2hCaEQsMnpDQThCQSw4b0JEakJZLGVBQWUsNEZBQUUsZ0NBQWdDLG9nQkFBRSw4QkFBOEI7OzRGQUdoRixtQ0FBbUM7a0JBVC9DLFNBQVM7K0JBRUUsZ0NBQWdDLGNBRzlCLElBQUksV0FDUCxDQUFDLGVBQWUsRUFBRSxnQ0FBZ0MsRUFBRSw4QkFBOEIsQ0FBQyxtQkFDM0UsdUJBQXVCLENBQUMsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDb21wb25lbnQsIGVmZmVjdCwgRWxlbWVudFJlZiwgaW5wdXQsIG1vZGVsLCBvdXRwdXQsIHZpZXdDaGlsZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTGlic1VpQ29tcG9uZW50c0JhZGdlQ29tcG9uZW50IH0gZnJvbSAnQGxpYnMtdWkvY29tcG9uZW50cy1iYWRnZSc7XG5pbXBvcnQgeyBMaWJzVWlDb21wb25lbnRzUG9wb3ZlckNvbXBvbmVudCB9IGZyb20gJ0BsaWJzLXVpL2NvbXBvbmVudHMtcG9wb3Zlcic7XG5pbXBvcnQgeyBjb2xvclN0ZXBDb250cmFzdEZyb21PcmlnaW4sIGVzY2FwZUh0bWwgfSBmcm9tICdAbGlicy11aS91dGlscyc7XG5pbXBvcnQgeyBUcmFuc2xhdGVNb2R1bGUgfSBmcm9tICdAbmd4LXRyYW5zbGF0ZS9jb3JlJztcbmltcG9ydCB7IElCdXR0b25UYWIsIElPdGhlckNvbmZpZyB9IGZyb20gJy4vaW50ZXJmYWNlcy90YWIuaW50ZXJmYWNlJztcblxuQENvbXBvbmVudCh7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAYW5ndWxhci1lc2xpbnQvY29tcG9uZW50LXNlbGVjdG9yXG4gIHNlbGVjdG9yOiAnbGlic191aS1jb21wb25lbnRzLWJ1dHRvbnMtdGFiJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3RhYi5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsOiAnLi90YWIuY29tcG9uZW50LnNjc3MnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbVHJhbnNsYXRlTW9kdWxlLCBMaWJzVWlDb21wb25lbnRzUG9wb3ZlckNvbXBvbmVudCwgTGlic1VpQ29tcG9uZW50c0JhZGdlQ29tcG9uZW50XSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIExpYnNVaUNvbXBvbmVudHNCdXR0b25zVGFiQ29tcG9uZW50IHtcbiAgcHJpdmF0ZSByZWFkb25seSBvdGhlclN0eWxlQ2xhc3NCdXR0b25UYWJFbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3N0eWxlJyk7XG5cbiAgLy8gI3JlZ2lvbiBJTlBVVFxuICByZWFkb25seSBpdGVtcyA9IGlucHV0LnJlcXVpcmVkPEFycmF5PElCdXR0b25UYWI+LCBBcnJheTxJQnV0dG9uVGFiPj4oeyB0cmFuc2Zvcm06IChkYXRhKSA9PiBkYXRhLm1hcCgoaXRlbSkgPT4gKHsgLi4uaXRlbSwgbGFiZWw6IGVzY2FwZUh0bWwoaXRlbS5sYWJlbCkgfSkpIH0pO1xuICByZWFkb25seSBkaXNhYmxlID0gaW5wdXQ8Ym9vbGVhbj4oZmFsc2UpO1xuICByZWFkb25seSBrZXlTZWxlY3RlZCA9IG1vZGVsPHN0cmluZz4oJycpO1xuICByZWFkb25seSBvdGhlckNvbmZpZyA9IGlucHV0PElPdGhlckNvbmZpZz4oKTsgLy8gcmVxdWlyZWQgYW5kIG9ubHkgYXBwbHkgd2hlbiB0eXBlIGlzIG90aGVyXG5cbiAgLy8gI3JlZ2lvbiBPVVRQVVRcbiAgcmVhZG9ubHkgb3V0S2V5U2VsZWN0ZWQgPSBvdXRwdXQ8c3RyaW5nPigpO1xuXG4gIC8qIFZJRVcgQ0hJTEQgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBidXR0b25FbCA9IHZpZXdDaGlsZDxFbGVtZW50UmVmPignYnV0dG9uRWwnKTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBlZmZlY3QoKCkgPT4ge1xuICAgICAgY29uc3QgY29uZmlnID0gdGhpcy5vdGhlckNvbmZpZygpO1xuXG4gICAgICBpZiAoY29uZmlnKSB7XG4gICAgICAgIGNvbnN0IGJhY2tncm91bmQgPSBjb25maWcuYmFja2dyb3VuZCB8fCBjb2xvclN0ZXBDb250cmFzdEZyb21PcmlnaW4oY29uZmlnLmNvbG9yLCA5NSk/LmxpZ2h0O1xuICAgICAgICBjb25zdCBiYWNrZ3JvdW5kQmFkZ2UgPSBjb25maWcuYmFja2dyb3VuZF9iYWRnZSB8fCBjb2xvclN0ZXBDb250cmFzdEZyb21PcmlnaW4oY29uZmlnLmNvbG9yLCA5MCk/LmxpZ2h0O1xuICAgICAgICBjb25zdCBzdHlsZXMgPSBgLmxpYnMtdWktYnV0dG9uLXRhYi1vdGhlclthY3RpdmU9XCJ0cnVlXCJdIHtcbiAgICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogJHtiYWNrZ3JvdW5kfSAhaW1wb3J0YW50O1xuICAgICAgICAgICAgfVxuICAgICAgICAgIFxuICAgICAgICAgICAgLmxpYnMtdWktYnV0dG9uLXRhYi1vdGhlclthY3RpdmU9XCJ0cnVlXCJdID4gLmxpYnMtdWktYnV0dG9uLXRhYi1sYWJlbCB7XG4gICAgICAgICAgICAgIGNvbG9yOiAke2NvbmZpZy5jb2xvcn0gIWltcG9ydGFudDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICBcbiAgICAgICAgICAgIC5saWJzLXVpLWJ1dHRvbi10YWItb3RoZXJbYWN0aXZlPVwidHJ1ZVwiXSA+IC5saWJzLXVpLWJ1dHRvbi10YWItYmFkZ2UgPiAubGlicy11aS1idXR0b24tdGFiLWJhZGdlLWNpcmNsZSB7XG4gICAgICAgICAgICAgIGNvbG9yOiAke2NvbmZpZy5jb2xvcn0gIWltcG9ydGFudDtcbiAgICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogJHtiYWNrZ3JvdW5kQmFkZ2V9ICFpbXBvcnRhbnQ7XG4gICAgICAgICAgICB9YDtcbiAgICAgICAgdGhpcy5vdGhlclN0eWxlQ2xhc3NCdXR0b25UYWJFbC5pbm5lckhUTUwgPSBzdHlsZXM7XG4gICAgICAgIHRoaXMuYnV0dG9uRWwoKT8ubmF0aXZlRWxlbWVudC5hcHBlbmQodGhpcy5vdGhlclN0eWxlQ2xhc3NCdXR0b25UYWJFbCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvKiBGVU5DVElPTlMgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGhhbmRsZXJTZWxlY3RJdGVtKGV2ZW50OiBFdmVudCwgaXRlbTogSUJ1dHRvblRhYikge1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIGlmICh0aGlzLmRpc2FibGUoKSB8fCBpdGVtLmRpc2FibGUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5rZXlTZWxlY3RlZC5zZXQoaXRlbS5rZXkpO1xuICAgIHRoaXMub3V0S2V5U2VsZWN0ZWQuZW1pdCh0aGlzLmtleVNlbGVjdGVkKCkpO1xuICB9XG59XG4iLCI8ZGl2XG4gICNidXR0b25FbFxuICBjbGFzcz1cImZsZXhcIj5cbiAgQGZvciAoaXRlbSBvZiBpdGVtcygpOyB0cmFjayBpdGVtKSB7XG4gICAgPGRpdlxuICAgICAgY2xhc3M9XCJmbGV4IGl0ZW1zLWNlbnRlciBsaWJzLXVpLWJ1dHRvbi10YWIge3sgJ2xpYnMtdWktYnV0dG9uLXRhYi0nICsgaXRlbS50eXBlIH19IHt7IGl0ZW0uY2xhc3MgfHwgJ3B4LVs4cHhdIG14LVs4cHhdIHB5LVs0cHhdJyB9fSB7eyBkaXNhYmxlKCkgfHwgaXRlbS5kaXNhYmxlID8gJ3BvaW50ZXItZXZlbnRzLW5vbmUgY3Vyc29yLWRlZmF1bHQnIDogJ2N1cnNvci1wb2ludGVyJyB9fVwiXG4gICAgICB0YWJpbmRleD1cIjBcIlxuICAgICAgW2F0dHIuYWN0aXZlXT1cIml0ZW0ua2V5ID09PSBrZXlTZWxlY3RlZCgpXCJcbiAgICAgIChjbGljayk9XCJoYW5kbGVyU2VsZWN0SXRlbSgkZXZlbnQsIGl0ZW0pXCJcbiAgICAgIChrZXlkb3duLmVudGVyKT1cImhhbmRsZXJTZWxlY3RJdGVtKCRhbnkoJGV2ZW50KSwgaXRlbSlcIlxuICAgICAgKGtleWRvd24uc3BhY2UpPVwiaGFuZGxlclNlbGVjdEl0ZW0oJGFueSgkZXZlbnQpLCBpdGVtKVwiPlxuICAgICAgPHNwYW5cbiAgICAgICAgTGlic1VpQ29tcG9uZW50c1BvcG92ZXJEaXJlY3RpdmVcbiAgICAgICAgY2xhc3M9XCJ3LWZ1bGwgbGlicy11aS1idXR0b24tdGFiLWxhYmVsIHt7IGl0ZW0uY2xhc3NMYWJlbCB8fCAnbGlicy11aS1mb250LWg2cicgfX1cIlxuICAgICAgICBbY2xhc3MubGlicy11aS1kaXNhYmxlXT1cImRpc2FibGUoKSB8fCBpdGVtLmRpc2FibGVcIlxuICAgICAgICBbdHlwZV09XCIndGV4dCdcIlxuICAgICAgICBbYXR0ci5hY3RpdmVdPVwiaXRlbS5rZXkgPT09IGtleVNlbGVjdGVkKClcIlxuICAgICAgICBbaWdub3JlU3RvcFByb3BhZ2F0aW9uRXZlbnRdPVwidHJ1ZVwiXG4gICAgICAgIFtpbm5lckh0bWxdPVwiaXRlbS5sYWJlbCB8IHRyYW5zbGF0ZVwiPjwvc3Bhbj5cbiAgICAgIEBpZiAoaXRlbS5jb3VudCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIDxsaWJzX3VpLWNvbXBvbmVudHMtYmFkZ2VcbiAgICAgICAgICBjbGFzcz1cImxpYnMtdWktYnV0dG9uLXRhYi1iYWRnZVwiXG4gICAgICAgICAgW21vZGVdPVwiaXRlbS5tb2RlQ291bnQgfHwgJ3grJ1wiXG4gICAgICAgICAgW2NvdW50XT1cIml0ZW0uY291bnRcIlxuICAgICAgICAgIFttYXhDb3VudF09XCJpdGVtLm1heENvdW50IHx8IDk5XCJcbiAgICAgICAgICBbY2xhc3NDaXJjbGVdPVwiJ2xpYnMtdWktYnV0dG9uLXRhYi1iYWRnZS1jaXJjbGUgbGlicy11aS1mb250LWg2cidcIiAvPlxuICAgICAgfVxuICAgIDwvZGl2PlxuICB9XG48L2Rpdj5cbiJdfQ==
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, model, output, viewChild, effect,
|
|
2
|
+
import { input, model, output, viewChild, effect, Component, ChangeDetectionStrategy } from '@angular/core';
|
|
3
3
|
import { LibsUiComponentsBadgeComponent } from '@libs-ui/components-badge';
|
|
4
4
|
import { LibsUiComponentsPopoverComponent } from '@libs-ui/components-popover';
|
|
5
5
|
import { escapeHtml, colorStepContrastFromOrigin } from '@libs-ui/utils';
|
|
@@ -50,11 +50,11 @@ class LibsUiComponentsButtonsTabComponent {
|
|
|
50
50
|
this.outKeySelected.emit(this.keySelected());
|
|
51
51
|
}
|
|
52
52
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiComponentsButtonsTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
53
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LibsUiComponentsButtonsTabComponent, isStandalone: true, selector: "libs_ui-components-buttons-tab", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, disable: { classPropertyName: "disable", publicName: "disable", isSignal: true, isRequired: false, transformFunction: null }, keySelected: { classPropertyName: "keySelected", publicName: "keySelected", isSignal: true, isRequired: false, transformFunction: null }, otherConfig: { classPropertyName: "otherConfig", publicName: "otherConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { keySelected: "keySelectedChange", outKeySelected: "outKeySelected" }, viewQueries: [{ propertyName: "buttonEl", first: true, predicate: ["buttonEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #buttonEl\n class=\"flex\">\n @for (item of items(); track item) {\n <div\n class=\"flex items-center libs-ui-button-tab {{ 'libs-ui-button-tab-' + item.type }} {{ item.class || 'px-[8px] mx-[8px] py-[4px]' }} {{ disable() || item.disable ? 'pointer-events-none cursor-default' : 'cursor-pointer' }}\"\n [attr.active]=\"item.key === keySelected()\"\n (click)=\"handlerSelectItem($event, item)\">\n <span\n LibsUiComponentsPopoverDirective\n class=\"w-full libs-ui-button-tab-label {{ item.classLabel || 'libs-ui-font-h6r' }}\"\n [class.libs-ui-disable]=\"disable() || item.disable\"\n [type]=\"'text'\"\n [attr.active]=\"item.key === keySelected()\"\n [ignoreStopPropagationEvent]=\"true\"\n [innerHtml]=\"item.label | translate\"></span>\n @if (item.count !== undefined) {\n <libs_ui-components-badge\n class=\"libs-ui-button-tab-badge\"\n [mode]=\"item.modeCount || 'x+'\"\n [count]=\"item.count\"\n [maxCount]=\"item.maxCount || 99\"\n [classCircle]=\"'libs-ui-button-tab-badge-circle libs-ui-font-h6r'\" />\n }\n </div>\n }\n</div>\n", styles: [":host ::ng-deep .libs-ui-button-tab{border-radius:4px}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover{background:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#e6e7ea}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "component", type: LibsUiComponentsPopoverComponent, selector: "libs_ui-components-popover,[LibsUiComponentsPopoverDirective]", inputs: ["debugId", "flagMouse", "type", "mode", "config", "ignoreShowPopover", "elementRefCustom", "initEventInElementRefCustom", "classInclude", "ignoreHiddenPopoverContentWhenMouseLeave", "ignoreStopPropagationEvent", "ignoreCursorPointerModeLikeClick", "isAddContentToParentDocument", "ignoreClickOutside"], outputs: ["outEvent", "outChangStageFlagMouse", "outEventPopoverContent", "outFunctionsControl"] }, { kind: "component", type: LibsUiComponentsBadgeComponent, selector: "libs_ui-components-badge", inputs: ["popoverConfig", "active", "count", "mode", "maxCount", "ignoreMarginDefault", "classCircle", "ignoreStopPropagationEvent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
53
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LibsUiComponentsButtonsTabComponent, isStandalone: true, selector: "libs_ui-components-buttons-tab", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, disable: { classPropertyName: "disable", publicName: "disable", isSignal: true, isRequired: false, transformFunction: null }, keySelected: { classPropertyName: "keySelected", publicName: "keySelected", isSignal: true, isRequired: false, transformFunction: null }, otherConfig: { classPropertyName: "otherConfig", publicName: "otherConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { keySelected: "keySelectedChange", outKeySelected: "outKeySelected" }, viewQueries: [{ propertyName: "buttonEl", first: true, predicate: ["buttonEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #buttonEl\n class=\"flex\">\n @for (item of items(); track item) {\n <div\n class=\"flex items-center libs-ui-button-tab {{ 'libs-ui-button-tab-' + item.type }} {{ item.class || 'px-[8px] mx-[8px] py-[4px]' }} {{ disable() || item.disable ? 'pointer-events-none cursor-default' : 'cursor-pointer' }}\"\n tabindex=\"0\"\n [attr.active]=\"item.key === keySelected()\"\n (click)=\"handlerSelectItem($event, item)\"\n (keydown.enter)=\"handlerSelectItem($any($event), item)\"\n (keydown.space)=\"handlerSelectItem($any($event), item)\">\n <span\n LibsUiComponentsPopoverDirective\n class=\"w-full libs-ui-button-tab-label {{ item.classLabel || 'libs-ui-font-h6r' }}\"\n [class.libs-ui-disable]=\"disable() || item.disable\"\n [type]=\"'text'\"\n [attr.active]=\"item.key === keySelected()\"\n [ignoreStopPropagationEvent]=\"true\"\n [innerHtml]=\"item.label | translate\"></span>\n @if (item.count !== undefined) {\n <libs_ui-components-badge\n class=\"libs-ui-button-tab-badge\"\n [mode]=\"item.modeCount || 'x+'\"\n [count]=\"item.count\"\n [maxCount]=\"item.maxCount || 99\"\n [classCircle]=\"'libs-ui-button-tab-badge-circle libs-ui-font-h6r'\" />\n }\n </div>\n }\n</div>\n", styles: [":host ::ng-deep .libs-ui-button-tab{border-radius:4px}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover{background:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#e6e7ea}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "component", type: LibsUiComponentsPopoverComponent, selector: "libs_ui-components-popover,[LibsUiComponentsPopoverDirective]", inputs: ["debugId", "flagMouse", "type", "mode", "config", "ignoreShowPopover", "elementRefCustom", "initEventInElementRefCustom", "classInclude", "ignoreHiddenPopoverContentWhenMouseLeave", "ignoreStopPropagationEvent", "ignoreCursorPointerModeLikeClick", "isAddContentToParentDocument", "ignoreClickOutside"], outputs: ["outEvent", "outChangStageFlagMouse", "outEventPopoverContent", "outFunctionsControl"] }, { kind: "component", type: LibsUiComponentsBadgeComponent, selector: "libs_ui-components-badge", inputs: ["popoverConfig", "active", "count", "mode", "maxCount", "ignoreMarginDefault", "classCircle", "ignoreStopPropagationEvent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
54
54
|
}
|
|
55
55
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiComponentsButtonsTabComponent, decorators: [{
|
|
56
56
|
type: Component,
|
|
57
|
-
args: [{ selector: 'libs_ui-components-buttons-tab', standalone: true, imports: [TranslateModule, LibsUiComponentsPopoverComponent, LibsUiComponentsBadgeComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n #buttonEl\n class=\"flex\">\n @for (item of items(); track item) {\n <div\n class=\"flex items-center libs-ui-button-tab {{ 'libs-ui-button-tab-' + item.type }} {{ item.class || 'px-[8px] mx-[8px] py-[4px]' }} {{ disable() || item.disable ? 'pointer-events-none cursor-default' : 'cursor-pointer' }}\"\n [attr.active]=\"item.key === keySelected()\"\n (click)=\"handlerSelectItem($event, item)\">\n <span\n LibsUiComponentsPopoverDirective\n class=\"w-full libs-ui-button-tab-label {{ item.classLabel || 'libs-ui-font-h6r' }}\"\n [class.libs-ui-disable]=\"disable() || item.disable\"\n [type]=\"'text'\"\n [attr.active]=\"item.key === keySelected()\"\n [ignoreStopPropagationEvent]=\"true\"\n [innerHtml]=\"item.label | translate\"></span>\n @if (item.count !== undefined) {\n <libs_ui-components-badge\n class=\"libs-ui-button-tab-badge\"\n [mode]=\"item.modeCount || 'x+'\"\n [count]=\"item.count\"\n [maxCount]=\"item.maxCount || 99\"\n [classCircle]=\"'libs-ui-button-tab-badge-circle libs-ui-font-h6r'\" />\n }\n </div>\n }\n</div>\n", styles: [":host ::ng-deep .libs-ui-button-tab{border-radius:4px}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover{background:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#e6e7ea}\n"] }]
|
|
57
|
+
args: [{ selector: 'libs_ui-components-buttons-tab', standalone: true, imports: [TranslateModule, LibsUiComponentsPopoverComponent, LibsUiComponentsBadgeComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n #buttonEl\n class=\"flex\">\n @for (item of items(); track item) {\n <div\n class=\"flex items-center libs-ui-button-tab {{ 'libs-ui-button-tab-' + item.type }} {{ item.class || 'px-[8px] mx-[8px] py-[4px]' }} {{ disable() || item.disable ? 'pointer-events-none cursor-default' : 'cursor-pointer' }}\"\n tabindex=\"0\"\n [attr.active]=\"item.key === keySelected()\"\n (click)=\"handlerSelectItem($event, item)\"\n (keydown.enter)=\"handlerSelectItem($any($event), item)\"\n (keydown.space)=\"handlerSelectItem($any($event), item)\">\n <span\n LibsUiComponentsPopoverDirective\n class=\"w-full libs-ui-button-tab-label {{ item.classLabel || 'libs-ui-font-h6r' }}\"\n [class.libs-ui-disable]=\"disable() || item.disable\"\n [type]=\"'text'\"\n [attr.active]=\"item.key === keySelected()\"\n [ignoreStopPropagationEvent]=\"true\"\n [innerHtml]=\"item.label | translate\"></span>\n @if (item.count !== undefined) {\n <libs_ui-components-badge\n class=\"libs-ui-button-tab-badge\"\n [mode]=\"item.modeCount || 'x+'\"\n [count]=\"item.count\"\n [maxCount]=\"item.maxCount || 99\"\n [classCircle]=\"'libs-ui-button-tab-badge-circle libs-ui-font-h6r'\" />\n }\n </div>\n }\n</div>\n", styles: [":host ::ng-deep .libs-ui-button-tab{border-radius:4px}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover{background:#f8f9fa}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-label]{color:#6a7383}:host ::ng-deep .libs-ui-button-tab:hover>[class*=libs-ui-button-tab-badge]>[class*=libs-ui-button-tab-badge-circle]{color:#6a7383;background-color:#e6e7ea}\n"] }]
|
|
58
58
|
}], ctorParameters: () => [] });
|
|
59
59
|
|
|
60
60
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"libs-ui-components-buttons-tab.mjs","sources":["../../../../../../libs-ui/components/buttons/tab/src/tab.component.ts","../../../../../../libs-ui/components/buttons/tab/src/tab.component.html","../../../../../../libs-ui/components/buttons/tab/src/libs-ui-components-buttons-tab.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, effect, ElementRef, input, model, output, viewChild } from '@angular/core';\nimport { LibsUiComponentsBadgeComponent } from '@libs-ui/components-badge';\nimport { LibsUiComponentsPopoverComponent } from '@libs-ui/components-popover';\nimport { colorStepContrastFromOrigin, escapeHtml } from '@libs-ui/utils';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { IButtonTab, IOtherConfig } from './interfaces/tab.interface';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-buttons-tab',\n templateUrl: './tab.component.html',\n styleUrl: './tab.component.scss',\n standalone: true,\n imports: [TranslateModule, LibsUiComponentsPopoverComponent, LibsUiComponentsBadgeComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class LibsUiComponentsButtonsTabComponent {\n private readonly otherStyleClassButtonTabEl = document.createElement('style');\n\n // #region INPUT\n readonly items = input.required<Array<IButtonTab>, Array<IButtonTab>>({ transform: (data) => data.map((item) => ({ ...item, label: escapeHtml(item.label) })) });\n readonly disable = input<boolean>(false);\n readonly keySelected = model<string>('');\n readonly otherConfig = input<IOtherConfig>(); // required and only apply when type is other\n\n // #region OUTPUT\n readonly outKeySelected = output<string>();\n\n /* VIEW CHILD */\n private readonly buttonEl = viewChild<ElementRef>('buttonEl');\n\n constructor() {\n effect(() => {\n const config = this.otherConfig();\n\n if (config) {\n const background = config.background || colorStepContrastFromOrigin(config.color, 95)?.light;\n const backgroundBadge = config.background_badge || colorStepContrastFromOrigin(config.color, 90)?.light;\n const styles = `.libs-ui-button-tab-other[active=\"true\"] {\n background-color: ${background} !important;\n }\n \n .libs-ui-button-tab-other[active=\"true\"] > .libs-ui-button-tab-label {\n color: ${config.color} !important;\n }\n \n .libs-ui-button-tab-other[active=\"true\"] > .libs-ui-button-tab-badge > .libs-ui-button-tab-badge-circle {\n color: ${config.color} !important;\n background-color: ${backgroundBadge} !important;\n }`;\n this.otherStyleClassButtonTabEl.innerHTML = styles;\n this.buttonEl()?.nativeElement.append(this.otherStyleClassButtonTabEl);\n }\n });\n }\n\n /* FUNCTIONS */\n protected async handlerSelectItem(event:
|
|
1
|
+
{"version":3,"file":"libs-ui-components-buttons-tab.mjs","sources":["../../../../../../libs-ui/components/buttons/tab/src/tab.component.ts","../../../../../../libs-ui/components/buttons/tab/src/tab.component.html","../../../../../../libs-ui/components/buttons/tab/src/libs-ui-components-buttons-tab.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, effect, ElementRef, input, model, output, viewChild } from '@angular/core';\nimport { LibsUiComponentsBadgeComponent } from '@libs-ui/components-badge';\nimport { LibsUiComponentsPopoverComponent } from '@libs-ui/components-popover';\nimport { colorStepContrastFromOrigin, escapeHtml } from '@libs-ui/utils';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { IButtonTab, IOtherConfig } from './interfaces/tab.interface';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-buttons-tab',\n templateUrl: './tab.component.html',\n styleUrl: './tab.component.scss',\n standalone: true,\n imports: [TranslateModule, LibsUiComponentsPopoverComponent, LibsUiComponentsBadgeComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class LibsUiComponentsButtonsTabComponent {\n private readonly otherStyleClassButtonTabEl = document.createElement('style');\n\n // #region INPUT\n readonly items = input.required<Array<IButtonTab>, Array<IButtonTab>>({ transform: (data) => data.map((item) => ({ ...item, label: escapeHtml(item.label) })) });\n readonly disable = input<boolean>(false);\n readonly keySelected = model<string>('');\n readonly otherConfig = input<IOtherConfig>(); // required and only apply when type is other\n\n // #region OUTPUT\n readonly outKeySelected = output<string>();\n\n /* VIEW CHILD */\n private readonly buttonEl = viewChild<ElementRef>('buttonEl');\n\n constructor() {\n effect(() => {\n const config = this.otherConfig();\n\n if (config) {\n const background = config.background || colorStepContrastFromOrigin(config.color, 95)?.light;\n const backgroundBadge = config.background_badge || colorStepContrastFromOrigin(config.color, 90)?.light;\n const styles = `.libs-ui-button-tab-other[active=\"true\"] {\n background-color: ${background} !important;\n }\n \n .libs-ui-button-tab-other[active=\"true\"] > .libs-ui-button-tab-label {\n color: ${config.color} !important;\n }\n \n .libs-ui-button-tab-other[active=\"true\"] > .libs-ui-button-tab-badge > .libs-ui-button-tab-badge-circle {\n color: ${config.color} !important;\n background-color: ${backgroundBadge} !important;\n }`;\n this.otherStyleClassButtonTabEl.innerHTML = styles;\n this.buttonEl()?.nativeElement.append(this.otherStyleClassButtonTabEl);\n }\n });\n }\n\n /* FUNCTIONS */\n protected async handlerSelectItem(event: Event, item: IButtonTab) {\n event.stopPropagation();\n if (this.disable() || item.disable) {\n return;\n }\n this.keySelected.set(item.key);\n this.outKeySelected.emit(this.keySelected());\n }\n}\n","<div\n #buttonEl\n class=\"flex\">\n @for (item of items(); track item) {\n <div\n class=\"flex items-center libs-ui-button-tab {{ 'libs-ui-button-tab-' + item.type }} {{ item.class || 'px-[8px] mx-[8px] py-[4px]' }} {{ disable() || item.disable ? 'pointer-events-none cursor-default' : 'cursor-pointer' }}\"\n tabindex=\"0\"\n [attr.active]=\"item.key === keySelected()\"\n (click)=\"handlerSelectItem($event, item)\"\n (keydown.enter)=\"handlerSelectItem($any($event), item)\"\n (keydown.space)=\"handlerSelectItem($any($event), item)\">\n <span\n LibsUiComponentsPopoverDirective\n class=\"w-full libs-ui-button-tab-label {{ item.classLabel || 'libs-ui-font-h6r' }}\"\n [class.libs-ui-disable]=\"disable() || item.disable\"\n [type]=\"'text'\"\n [attr.active]=\"item.key === keySelected()\"\n [ignoreStopPropagationEvent]=\"true\"\n [innerHtml]=\"item.label | translate\"></span>\n @if (item.count !== undefined) {\n <libs_ui-components-badge\n class=\"libs-ui-button-tab-badge\"\n [mode]=\"item.modeCount || 'x+'\"\n [count]=\"item.count\"\n [maxCount]=\"item.maxCount || 99\"\n [classCircle]=\"'libs-ui-button-tab-badge-circle libs-ui-font-h6r'\" />\n }\n </div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;MAgBa,mCAAmC,CAAA;AAC7B,IAAA,0BAA0B,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;;AAGrE,IAAA,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAuC,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AACxJ,IAAA,OAAO,GAAG,KAAK,CAAU,KAAK,CAAC,CAAC;AAChC,IAAA,WAAW,GAAG,KAAK,CAAS,EAAE,CAAC,CAAC;AAChC,IAAA,WAAW,GAAG,KAAK,EAAgB,CAAC;;IAGpC,cAAc,GAAG,MAAM,EAAU,CAAC;;AAG1B,IAAA,QAAQ,GAAG,SAAS,CAAa,UAAU,CAAC,CAAC;AAE9D,IAAA,WAAA,GAAA;QACE,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YAElC,IAAI,MAAM,EAAE;AACV,gBAAA,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,2BAA2B,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,KAAK,CAAC;AAC7F,gBAAA,MAAM,eAAe,GAAG,MAAM,CAAC,gBAAgB,IAAI,2BAA2B,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,KAAK,CAAC;AACxG,gBAAA,MAAM,MAAM,GAAG,CAAA;kCACW,UAAU,CAAA;;;;AAIrB,qBAAA,EAAA,MAAM,CAAC,KAAK,CAAA;;;;AAIZ,qBAAA,EAAA,MAAM,CAAC,KAAK,CAAA;kCACD,eAAe,CAAA;cACnC,CAAC;AACP,gBAAA,IAAI,CAAC,0BAA0B,CAAC,SAAS,GAAG,MAAM,CAAC;AACnD,gBAAA,IAAI,CAAC,QAAQ,EAAE,EAAE,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;aACxE;AACH,SAAC,CAAC,CAAC;KACJ;;AAGS,IAAA,MAAM,iBAAiB,CAAC,KAAY,EAAE,IAAgB,EAAA;QAC9D,KAAK,CAAC,eAAe,EAAE,CAAC;QACxB,IAAI,IAAI,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE;YAClC,OAAO;SACR;QACD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;KAC9C;wGAhDU,mCAAmC,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAnC,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,mCAAmC,szBChBhD,2zCA8BA,EAAA,MAAA,EAAA,CAAA,ulBAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDjBY,eAAe,EAAE,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,IAAA,EAAA,WAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,gCAAgC,ogBAAE,8BAA8B,EAAA,QAAA,EAAA,0BAAA,EAAA,MAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,OAAA,EAAA,MAAA,EAAA,UAAA,EAAA,qBAAA,EAAA,aAAA,EAAA,4BAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAGhF,mCAAmC,EAAA,UAAA,EAAA,CAAA;kBAT/C,SAAS;AAEE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,gCAAgC,EAG9B,UAAA,EAAA,IAAI,EACP,OAAA,EAAA,CAAC,eAAe,EAAE,gCAAgC,EAAE,8BAA8B,CAAC,EAC3E,eAAA,EAAA,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,2zCAAA,EAAA,MAAA,EAAA,CAAA,ulBAAA,CAAA,EAAA,CAAA;;;AEdjD;;AAEG;;;;"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libs-ui/components-buttons-tab",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.357-1",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"@angular/core": ">=18.0.0",
|
|
6
|
-
"@libs-ui/components-badge": "0.2.
|
|
7
|
-
"@libs-ui/components-popover": "0.2.
|
|
8
|
-
"@libs-ui/utils": "0.2.
|
|
6
|
+
"@libs-ui/components-badge": "0.2.357-1",
|
|
7
|
+
"@libs-ui/components-popover": "0.2.357-1",
|
|
8
|
+
"@libs-ui/utils": "0.2.357-1",
|
|
9
9
|
"@ngx-translate/core": "^15.0.0"
|
|
10
10
|
},
|
|
11
11
|
"sideEffects": false,
|
package/tab.component.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export declare class LibsUiComponentsButtonsTabComponent {
|
|
|
9
9
|
readonly outKeySelected: import("@angular/core").OutputEmitterRef<string>;
|
|
10
10
|
private readonly buttonEl;
|
|
11
11
|
constructor();
|
|
12
|
-
protected handlerSelectItem(event:
|
|
12
|
+
protected handlerSelectItem(event: Event, item: IButtonTab): Promise<void>;
|
|
13
13
|
static ɵfac: i0.ɵɵFactoryDeclaration<LibsUiComponentsButtonsTabComponent, never>;
|
|
14
14
|
static ɵcmp: i0.ɵɵComponentDeclaration<LibsUiComponentsButtonsTabComponent, "libs_ui-components-buttons-tab", never, { "items": { "alias": "items"; "required": true; "isSignal": true; }; "disable": { "alias": "disable"; "required": false; "isSignal": true; }; "keySelected": { "alias": "keySelected"; "required": false; "isSignal": true; }; "otherConfig": { "alias": "otherConfig"; "required": false; "isSignal": true; }; }, { "keySelected": "keySelectedChange"; "outKeySelected": "outKeySelected"; }, never, never, true, never>;
|
|
15
15
|
}
|