@libs-ui/components-buttons-tab 0.2.356-41 → 0.2.356-43

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
- # Buttons Tab Component
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 dùng để hiển thị danh sách tab theo dạng button. Component hỗ trợ hiển thị badge count cho từng tab và cho phép disable toàn bộ hoặc disable từng tab.
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ẻ, 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 theo danh sách `items`
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
- - ✅ Disable toàn bộ hoặc disable từng tab item
18
- - ✅ Tuỳ biến màu với `otherConfig` khi `type = 'other'`
19
- - ✅ OnPush Change Detection
20
- - ✅ Angular Signals
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 { Component } from '@angular/core';
32
- import { LibsUiComponentsButtonsTabComponent, IButtonTab, IOtherConfig, TYPE_BUTTON_TAB } from '@libs-ui/components-buttons-tab';
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
- template: '',
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
- ## Cách sử dụng
88
+ ### 2. With Badge — Badge count cho từng tab
43
89
 
44
- ### 1. Ví dụ inline template
90
+ `example-badge.component.html`
45
91
 
46
92
  ```html
47
93
  <libs_ui-components-buttons-tab
48
- [items]="items"
94
+ [items]="itemsWithBadge"
49
95
  [(keySelected)]="selectedKey"
50
- (outKeySelected)="onKeySelected($event)"
96
+ (outKeySelected)="handlerKeySelected($event)"
51
97
  />
52
98
  ```
53
99
 
100
+ `example-badge.component.ts`
101
+
54
102
  ```typescript
55
- import { Component, signal } from '@angular/core';
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
- template: `
62
- <libs_ui-components-buttons-tab
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 InlineExampleComponent {
70
- readonly selectedKey = signal<string>('overview');
113
+ export class ExampleBadgeComponent {
114
+ protected selectedKey = model<string>('inbox');
71
115
 
72
- readonly items: IButtonTab[] = [
73
- { key: 'overview', label: 'Overview', type: 'blue' },
74
- { key: 'details', label: 'Details', type: 'green' },
75
- { key: 'settings', label: 'Settings', type: 'orange' },
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
- onKeySelected(key: string): void {
79
- this.selectedKey.set(key);
122
+ protected handlerKeySelected(event: Event): void {
123
+ event.stopPropagation();
80
124
  }
81
125
  }
82
126
  ```
83
127
 
84
- ### 2. dụ với file HTML riêng
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, signal } from '@angular/core';
100
- import { LibsUiComponentsButtonsTabComponent, IButtonTab, IOtherConfig } from '@libs-ui/components-buttons-tab';
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 HtmlFileExampleComponent {
108
- readonly selectedKey = signal<string>('custom-1');
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 items: IButtonTab[] = [
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, modeCount: 'x+' },
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
- ## Công nghệ
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
- ## API
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
- ### libs_ui-components-buttons-tab
242
+ ## @Output()
135
243
 
136
- #### Inputs
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
- | Property | Type | Default | Description |
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
- #### Outputs
250
+ dụ handler nhận đúng kiểu:
146
251
 
147
- | Property | Type | Description |
148
- |----------|------|-------------|
149
- | `(outKeySelected)` | `EventEmitter<string>` | Emit key mỗi khi người dùng chọn tab |
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
- export type TYPE_BUTTON_TAB = 'blue' | 'green' | 'red' | 'orange' | 'yellow' | 'cyan' | 'purple' | 'brown' | 'other' | string;
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
- ### tả Types
343
+ 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
- - **IButtonTab**: Cấu hình cho từng tab item, có thể kèm badge count và tuỳ chỉnh class/disable.
179
- - **IOtherConfig**: Cấu hình màu tuỳ biến cho type `other`.
180
- - **TYPE_BUTTON_TAB**: Danh sách type màu hỗ trợ (thể mở rộng bằng string).
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 tab nào `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
-
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, model, output, viewChild, effect, ChangeDetectionStrategy, Component } from '@angular/core';
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';
@@ -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: 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":"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"}
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":"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"}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@libs-ui/components-buttons-tab",
3
- "version": "0.2.356-41",
3
+ "version": "0.2.356-43",
4
4
  "peerDependencies": {
5
5
  "@angular/core": ">=18.0.0",
6
- "@libs-ui/components-badge": "0.2.356-41",
7
- "@libs-ui/components-popover": "0.2.356-41",
8
- "@libs-ui/utils": "0.2.356-41",
6
+ "@libs-ui/components-badge": "0.2.356-43",
7
+ "@libs-ui/components-popover": "0.2.356-43",
8
+ "@libs-ui/utils": "0.2.356-43",
9
9
  "@ngx-translate/core": "^15.0.0"
10
10
  },
11
11
  "sideEffects": false,