@libs-ui/components-buttons-dropdown 0.2.356-42 → 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,44 +1,45 @@
1
1
  # @libs-ui/components-buttons-dropdown
2
2
 
3
- > Component Dropdown Button với menu tùy chọn, hỗ trợ chế độ apply ngay hoặc apply sau.
3
+ > Dropdown button với menu tùy chọn dạng popover, hỗ trợ hai chế độ: apply ngay khi chọn hoặc chọn trước rồi xác nhận sau.
4
4
 
5
5
  ## Giới thiệu
6
6
 
7
- `LibsUiComponentsButtonsDropdownComponent` là một standalone Angular component được thiết kế để hiển thị button với dropdown menu. Component hỗ trợ 2 chế độ: apply ngay (applyNow) khi chọn item hoặc chọn trước rồi bấm nút Apply.
7
+ `LibsUiComponentsButtonsDropdownComponent` là một standalone Angular component kết hợp button popover menu thành một khối tương tác hoàn chỉnh. Component cung cấp hai chế độ hoạt động: `applyNow = true` để emit ngay khi user chọn item, hoặc `applyNow = false` để tách biệt nút mở menu và nút xác nhận (Apply). Nội dung item được sanitize tự động qua `escapeHtml` để ngăn XSS.
8
8
 
9
- ### Tính năng
9
+ ## Tính năng
10
10
 
11
- - ✅ 2 chế độ: Apply ngay hoặc Apply sau
12
- - ✅ Tùy chỉnh field hiển thị key field
13
- - ✅ Two-way binding cho item được chọn
14
- - ✅ Tích hợp popover với nhiều tùy chọn vị trí
15
- - ✅ Hỗ trợ icon cho từng item
16
- - ✅ Hỗ trợ custom template cho item
17
- - ✅ Disable state cho button từng item
18
- - ✅ Angular Signals cho tính phản hồi cao
19
- - ✅ OnPush Change Detection tối ưu hiệu năng
11
+ - ✅ Hai chế độ hoạt động: apply ngay (`applyNow = true`) hoặc chọn rồi xác nhận (`applyNow = false`)
12
+ - ✅ Two-way binding cho item đang được chọn qua `[(keySelected)]`
13
+ - ✅ Tùy chỉnh tên field hiển thị (`fieldDisplay`) và field key (`keyField`) — không cần format lại data
14
+ - ✅ Hỗ trợ icon bên trái cho từng item qua `fieldClassIconLeft`
15
+ - ✅ Custom sub-template cho item (`subTemplate`) và button lồng trong item (`buttonTemplateConfig`)
16
+ - ✅ Popover cấu hình linh hoạt: hướng mở, kích thước, z-index, animation
17
+ - ✅ Truy cập programmatic qua getter `FunctionsControl` để mở/đóng popup từ bên ngoài
18
+ - ✅ XSS-safe: giá trị `fieldDisplay` của mọi item tự động qua `escapeHtml`
19
+ - ✅ Hỗ trợ disable toàn bộ button hoặc từng item riêng lẻ
20
+ - ✅ Angular Signals + `ChangeDetectionStrategy.OnPush` — hiệu năng tối ưu
20
21
 
21
22
  ## Khi nào sử dụng
22
23
 
23
- - Khi cần hiển thị danh sách tùy chọn trong dropdown menu
24
- - Khi cần cho phép user chọn một item từ danh sách
25
- - Khi cần chế độ preview trước khi apply (applyNow = false)
26
- - Phù hợp cho filter buttons, action menus, selection dropdowns
24
+ - Cần button gọi menu dropdown chọn một giá trị (filter, sort, action)
25
+ - Cần tách luồng "chọn trước — xác nhận sau" (ví dụ: chọn kỳ báo cáo rồi bấm Apply)
26
+ - Cần action menu với icon label cho từng mục
27
+ - Cần dropdown lồng popover với vị trí kích thước tùy chỉnh theo context giao diện
27
28
 
28
29
  ## Cài đặt
29
30
 
30
31
  ```bash
31
- # npm
32
32
  npm install @libs-ui/components-buttons-dropdown
33
-
34
- # yarn
35
- yarn add @libs-ui/components-buttons-dropdown
36
33
  ```
37
34
 
38
35
  ## Import
39
36
 
40
37
  ```typescript
41
- import { LibsUiComponentsButtonsDropdownComponent, IButtonDropdown, IPopupConfigButtonDropdown } from '@libs-ui/components-buttons-dropdown';
38
+ import {
39
+ LibsUiComponentsButtonsDropdownComponent,
40
+ IButtonDropdown,
41
+ IPopupConfigButtonDropdown,
42
+ } from '@libs-ui/components-buttons-dropdown';
42
43
 
43
44
  @Component({
44
45
  standalone: true,
@@ -48,260 +49,444 @@ import { LibsUiComponentsButtonsDropdownComponent, IButtonDropdown, IPopupConfig
48
49
  export class YourComponent {}
49
50
  ```
50
51
 
51
- ## Ví dụ
52
+ ## Ví dụ sử dụng
53
+
54
+ ### 1. Apply ngay — chọn là emit
55
+
56
+ ```typescript
57
+ // component.ts
58
+ import { Component } from '@angular/core';
59
+ import { LibsUiComponentsButtonsDropdownComponent } from '@libs-ui/components-buttons-dropdown';
52
60
 
53
- ### Basic - Apply Ngay
61
+ @Component({
62
+ selector: 'app-example',
63
+ standalone: true,
64
+ imports: [LibsUiComponentsButtonsDropdownComponent],
65
+ templateUrl: './example.component.html',
66
+ })
67
+ export class ExampleComponent {
68
+ readonly statusOptions = [
69
+ { key: 'active', label: 'Đang hoạt động' },
70
+ { key: 'inactive', label: 'Ngừng hoạt động' },
71
+ { key: 'pending', label: 'Chờ duyệt' },
72
+ ];
73
+
74
+ handlerSelectStatus(event: Event, item: { key: string; label: string }): void {
75
+ event.stopPropagation();
76
+ console.log('Đã chọn:', item);
77
+ }
78
+ }
79
+ ```
54
80
 
55
81
  ```html
82
+ <!-- example.component.html -->
56
83
  <libs_ui-components-buttons-dropdown
57
- label="Select Option"
58
- [items]="options"
84
+ label="Trạng thái"
85
+ [items]="statusOptions"
59
86
  [applyNow]="true"
60
- (outSelectItem)="handleSelect($event)" />
87
+ (outSelectItem)="handlerSelectStatus($event, $event)" />
61
88
  ```
62
89
 
90
+ ### 2. Chọn trước — xác nhận sau (applyNow = false)
91
+
63
92
  ```typescript
64
- options = [
65
- { key: '1', label: 'Option 1' },
66
- { key: '2', label: 'Option 2' },
67
- { key: '3', label: 'Option 3' }
68
- ];
69
-
70
- handleSelect(item: any) {
71
- console.log('Selected:', item);
93
+ // component.ts
94
+ import { Component, signal } from '@angular/core';
95
+ import { LibsUiComponentsButtonsDropdownComponent } from '@libs-ui/components-buttons-dropdown';
96
+
97
+ @Component({
98
+ selector: 'app-filter',
99
+ standalone: true,
100
+ imports: [LibsUiComponentsButtonsDropdownComponent],
101
+ templateUrl: './filter.component.html',
102
+ })
103
+ export class FilterComponent {
104
+ protected selectedPeriodKey = signal<string>('q1');
105
+
106
+ readonly periodOptions = [
107
+ { key: 'q1', label: 'Quý 1' },
108
+ { key: 'q2', label: 'Quý 2' },
109
+ { key: 'q3', label: 'Quý 3' },
110
+ { key: 'q4', label: 'Quý 4' },
111
+ ];
112
+
113
+ handlerApplyPeriod(event: Event, item: { key: string; label: string }): void {
114
+ event.stopPropagation();
115
+ console.log('Áp dụng kỳ:', item);
116
+ }
72
117
  }
73
118
  ```
74
119
 
75
- ### With Apply Button
76
-
77
120
  ```html
121
+ <!-- filter.component.html -->
78
122
  <libs_ui-components-buttons-dropdown
79
- label="Select Option"
80
- [items]="options"
123
+ label="Chọn kỳ"
124
+ [items]="periodOptions"
81
125
  [applyNow]="false"
82
- [(keySelected)]="selectedKey"
83
- (outApply)="handleApply($event)" />
126
+ [(keySelected)]="selectedPeriodKey"
127
+ (outApply)="handlerApplyPeriod($event, $event)" />
84
128
  ```
85
129
 
130
+ ### 3. Custom tên field — data không cần format lại
131
+
86
132
  ```typescript
87
- selectedKey = '1';
133
+ // component.ts
134
+ import { Component } from '@angular/core';
135
+ import { LibsUiComponentsButtonsDropdownComponent } from '@libs-ui/components-buttons-dropdown';
88
136
 
89
- handleApply(item: any) {
90
- console.log('Applied:', item);
137
+ @Component({
138
+ selector: 'app-user-picker',
139
+ standalone: true,
140
+ imports: [LibsUiComponentsButtonsDropdownComponent],
141
+ templateUrl: './user-picker.component.html',
142
+ })
143
+ export class UserPickerComponent {
144
+ readonly users = [
145
+ { userId: 'u1', fullName: 'Nguyễn Văn An' },
146
+ { userId: 'u2', fullName: 'Trần Thị Bình' },
147
+ { userId: 'u3', fullName: 'Lê Quốc Cường' },
148
+ ];
149
+
150
+ handlerSelectUser(event: Event, user: { userId: string; fullName: string }): void {
151
+ event.stopPropagation();
152
+ console.log('Người được chọn:', user.fullName);
153
+ }
91
154
  }
92
155
  ```
93
156
 
94
- ### Custom Field Names
95
-
96
157
  ```html
158
+ <!-- user-picker.component.html -->
97
159
  <libs_ui-components-buttons-dropdown
98
- label="Select User"
160
+ label="Chọn người dùng"
99
161
  [items]="users"
100
- fieldDisplay="name"
101
- keyField="id"
162
+ fieldDisplay="fullName"
163
+ keyField="userId"
102
164
  [applyNow]="true"
103
- (outSelectItem)="handleSelect($event)" />
165
+ (outSelectItem)="handlerSelectUser($event, $event)" />
104
166
  ```
105
167
 
168
+ ### 4. Items có icon
169
+
106
170
  ```typescript
107
- users = [
108
- { id: 'u1', name: 'John Doe' },
109
- { id: 'u2', name: 'Jane Smith' },
110
- { id: 'u3', name: 'Bob Johnson' },
111
- ];
112
- ```
171
+ // component.ts
172
+ import { Component } from '@angular/core';
173
+ import { LibsUiComponentsButtonsDropdownComponent } from '@libs-ui/components-buttons-dropdown';
113
174
 
114
- ### With Icons
175
+ @Component({
176
+ selector: 'app-action-menu',
177
+ standalone: true,
178
+ imports: [LibsUiComponentsButtonsDropdownComponent],
179
+ templateUrl: './action-menu.component.html',
180
+ })
181
+ export class ActionMenuComponent {
182
+ readonly actionItems = [
183
+ { key: 'edit', label: 'Chỉnh sửa', classIconLeft: 'libs-ui-icon-edit' },
184
+ { key: 'duplicate', label: 'Nhân bản', classIconLeft: 'libs-ui-icon-copy' },
185
+ { key: 'delete', label: 'Xóa', classIconLeft: 'libs-ui-icon-delete' },
186
+ ];
187
+
188
+ handlerSelectAction(event: Event, action: { key: string; label: string }): void {
189
+ event.stopPropagation();
190
+ console.log('Hành động:', action.key);
191
+ }
192
+ }
193
+ ```
115
194
 
116
195
  ```html
196
+ <!-- action-menu.component.html -->
117
197
  <libs_ui-components-buttons-dropdown
118
- label="Actions"
119
- [items]="actions"
120
- fieldClassIconLeft="iconClass"
198
+ label="Thao tác"
199
+ [items]="actionItems"
200
+ fieldClassIconLeft="classIconLeft"
121
201
  [applyNow]="true"
122
- (outSelectItem)="handleAction($event)" />
202
+ (outSelectItem)="handlerSelectAction($event, $event)" />
123
203
  ```
124
204
 
205
+ ### 5. Tùy chỉnh cấu hình popover
206
+
125
207
  ```typescript
126
- actions = [
127
- { key: 'edit', label: 'Edit', iconClass: 'libs-ui-icon-edit' },
128
- { key: 'delete', label: 'Delete', iconClass: 'libs-ui-icon-delete' },
129
- { key: 'share', label: 'Share', iconClass: 'libs-ui-icon-share' },
130
- ];
131
- ```
208
+ // component.ts
209
+ import { Component } from '@angular/core';
210
+ import {
211
+ LibsUiComponentsButtonsDropdownComponent,
212
+ IPopupConfigButtonDropdown,
213
+ } from '@libs-ui/components-buttons-dropdown';
214
+
215
+ @Component({
216
+ selector: 'app-custom-popup',
217
+ standalone: true,
218
+ imports: [LibsUiComponentsButtonsDropdownComponent],
219
+ templateUrl: './custom-popup.component.html',
220
+ })
221
+ export class CustomPopupComponent {
222
+ readonly menuItems = [
223
+ { key: '1', label: 'Mục 1' },
224
+ { key: '2', label: 'Mục 2' },
225
+ { key: '3', label: 'Mục 3' },
226
+ ];
227
+
228
+ readonly popupConfig: IPopupConfigButtonDropdown = {
229
+ width: 280,
230
+ maxHeight: 200,
231
+ direction: 'bottom',
232
+ zIndex: 1500,
233
+ position: { mode: 'end', distance: 0 },
234
+ };
132
235
 
133
- ### Custom Popup Config
236
+ handlerSelectMenu(event: Event, item: { key: string }): void {
237
+ event.stopPropagation();
238
+ console.log('Chọn:', item.key);
239
+ }
240
+ }
241
+ ```
134
242
 
135
243
  ```html
244
+ <!-- custom-popup.component.html -->
136
245
  <libs_ui-components-buttons-dropdown
137
- label="Options"
138
- [items]="options"
139
- [popupConfig]="{
140
- width: 300,
141
- maxHeight: 200,
142
- direction: 'bottom',
143
- zIndex: 1500
144
- }"
145
- [applyNow]="true" />
246
+ label="Tùy chọn"
247
+ [items]="menuItems"
248
+ [popupConfig]="popupConfig"
249
+ [applyNow]="true"
250
+ (outSelectItem)="handlerSelectMenu($event, $event)" />
146
251
  ```
147
252
 
148
- ### Different Button Types
253
+ ### 6. Các kiểu button (typeButton)
149
254
 
150
255
  ```html
151
- <!-- Primary -->
152
- <libs_ui-components-buttons-dropdown
153
- label="Primary"
154
- [items]="options"
155
- typeButton="button-primary"
156
- [applyNow]="true" />
256
+ <div class="flex gap-2">
257
+ <libs_ui-components-buttons-dropdown
258
+ label="Primary"
259
+ [items]="menuItems"
260
+ typeButton="button-primary"
261
+ [applyNow]="true" />
262
+
263
+ <libs_ui-components-buttons-dropdown
264
+ label="Secondary"
265
+ [items]="menuItems"
266
+ typeButton="button-secondary"
267
+ [applyNow]="true" />
268
+
269
+ <libs_ui-components-buttons-dropdown
270
+ label="Outline"
271
+ [items]="menuItems"
272
+ typeButton="button-outline"
273
+ [applyNow]="true" />
274
+ </div>
275
+ ```
157
276
 
158
- <!-- Secondary -->
159
- <libs_ui-components-buttons-dropdown
160
- label="Secondary"
161
- [items]="options"
162
- typeButton="button-secondary"
163
- [applyNow]="true" />
277
+ ### 7. Truy cập programmatic qua FunctionsControl (ViewChild)
278
+
279
+ ```typescript
280
+ // parent.component.ts
281
+ import { Component, viewChild } from '@angular/core';
282
+ import { LibsUiComponentsButtonsDropdownComponent } from '@libs-ui/components-buttons-dropdown';
283
+
284
+ @Component({
285
+ selector: 'app-parent',
286
+ standalone: true,
287
+ imports: [LibsUiComponentsButtonsDropdownComponent],
288
+ templateUrl: './parent.component.html',
289
+ })
290
+ export class ParentComponent {
291
+ private readonly dropdownRef = viewChild<LibsUiComponentsButtonsDropdownComponent>('dropdownRef');
292
+
293
+ handlerOpenDropdown(event: Event): void {
294
+ event.stopPropagation();
295
+ this.dropdownRef()?.FunctionsControl?.show?.();
296
+ }
297
+
298
+ handlerCloseDropdown(event: Event): void {
299
+ event.stopPropagation();
300
+ this.dropdownRef()?.FunctionsControl?.hide?.();
301
+ }
302
+ }
303
+ ```
164
304
 
165
- <!-- Outline -->
305
+ ```html
306
+ <!-- parent.component.html -->
166
307
  <libs_ui-components-buttons-dropdown
167
- label="Outline"
168
- [items]="options"
169
- typeButton="button-outline"
170
- [applyNow]="true" />
308
+ #dropdownRef
309
+ label="Menu"
310
+ [items]="menuItems"
311
+ [applyNow]="true"
312
+ (outFunctionsControl)="handlerFunctionsControl($event)" />
171
313
  ```
172
314
 
173
- ## API
174
-
175
- ### libs_ui-components-buttons-dropdown
176
-
177
- #### Inputs
178
-
179
- | Property | Type | Default | Description |
180
- | -------------------------------------------- | ---------------------------- | ------------------------------------------ | ------------------------------------------------- |
181
- | `[applyNow]` | `boolean` | `false` | Nếu true: chọn xong tự emit; false: cần bấm Apply |
182
- | `[classIconLeft]` | `string` | `''` | Class icon bên trái button |
183
- | `[classIconRight]` | `string` | `'libs-ui-icon-move-right rotate-[90deg]'` | Class icon bên phải button |
184
- | `[classInclude]` | `string` | `''` | Class CSS bổ sung cho button |
185
- | `[classIncludeContainer]` | `string` | `undefined` | Class CSS cho container |
186
- | `[classLabel]` | `string` | `''` | Class CSS cho label |
187
- | `[disable]` | `boolean` | `false` | Disable button |
188
- | `[fieldClass]` | `string` | `'class'` | Tên field chứa class của item |
189
- | `[fieldClassIconLeft]` | `string` | `'classIconLeft'` | Tên field chứa icon class của item |
190
- | `[fieldDisplay]` | `string` | `'label'` | Tên field hiển thị của item |
191
- | `[iconOnlyType]` | `boolean` | `false` | Chỉ hiển thị icon, ẩn label |
192
- | `[ignoreHiddenPopoverContentWhenMouseLeave]` | `boolean` | `true` | Giữ popover mở khi chuột rời |
193
- | `[items]` | `Array<any>` | required | Danh sách items hiển thị |
194
- | `[keyField]` | `string` | `'key'` | Tên field làm key của item |
195
- | `[(keySelected)]` | `string` | `undefined` | Key của item được chọn (two-way binding) |
196
- | `[label]` | `string` | `undefined` | Label của button |
197
- | `[modePopover]` | `TYPE_POPOVER_MODE` | `'click-toggle'` | Chế độ hiển thị popover |
198
- | `[popupConfig]` | `IPopupConfigButtonDropdown` | `{...}` | Cấu hình popup (width, height, direction...) |
199
- | `[showBorderBottom]` | `boolean` | `false` | Hiển thị border dưới items |
200
- | `[sizeButton]` | `TYPE_SIZE_BUTTON` | `'medium'` | Kích thước button |
201
- | `[typeButton]` | `TYPE_BUTTON` | `'button-primary'` | Kiểu button |
202
-
203
- #### Outputs
204
-
205
- | Property | Type | Description |
206
- | ----------------------- | ------------------------------ | ------------------------------------------ |
207
- | `(outApply)` | `any` | Emit khi bấm Apply (chế độ applyNow=false) |
208
- | `(outFunctionsControl)` | `IPopoverFunctionControlEvent` | Emit functions điều khiển popover |
209
- | `(outHover)` | `boolean` | Emit khi hover state thay đổi |
210
- | `(outIconEvent)` | `MouseEvent` | Emit khi click icon |
211
- | `(outPopoverEvent)` | `TYPE_POPOVER_EVENT` | Emit events từ popover |
212
- | `(outSelectItem)` | `any` | Emit khi chọn item |
213
-
214
- #### Public Methods
215
-
216
- | Method | Description |
217
- | ------------------ | --------------------------------------- |
218
- | `FunctionsControl` | Getter để lấy popover control functions |
315
+ ## @Input()
316
+
317
+ | Input | Type | Default | Mô tả | Ví dụ |
318
+ |---|---|---|---|---|
319
+ | `[applyNow]` | `boolean` | `false` | `true`: emit ngay khi chọn item; `false`: tách nút mở menu và nút Apply | `[applyNow]="true"` |
320
+ | `[classIconLeft]` | `string` | `''` | Class icon hiển thị bên trái label trên button chính | `classIconLeft="libs-ui-icon-filter"` |
321
+ | `[classIconRight]` | `string` | `'libs-ui-icon-move-right rotate-[90deg]'` | Class icon mũi tên bên phải trên nút toggle menu (chế độ `applyNow=false`) | `classIconRight="libs-ui-icon-chevron-down"` |
322
+ | `[classInclude]` | `string` | `''` | Class CSS bổ sung cho button | `classInclude="w-full"` |
323
+ | `[classIncludeContainer]` | `string` | `undefined` | Class CSS bổ sung cho div container bọc ngoài | `classIncludeContainer="flex-1"` |
324
+ | `[classLabel]` | `string` | `''` | Class CSS cho label text trên button | `classLabel="libs-ui-font-h5m"` |
325
+ | `[disable]` | `boolean` | `false` | Disable toàn bộ button | `[disable]="isLoading()"` |
326
+ | `[fieldClass]` | `string` | `'class'` | Tên field trong object item chứa class CSS của item đó | `fieldClass="cssClass"` |
327
+ | `[fieldClassIconLeft]` | `string` | `'classIconLeft'` | Tên field trong object item chứa class icon bên trái | `fieldClassIconLeft="iconClass"` |
328
+ | `[fieldDisplay]` | `string` | `'label'` | Tên field trong object item dùng để hiển thị text | `fieldDisplay="name"` |
329
+ | `[iconOnlyType]` | `boolean` | `false` | Chỉ hiển thị icon, ẩn label trên button | `[iconOnlyType]="true"` |
330
+ | `[ignoreHiddenPopoverContentWhenMouseLeave]` | `boolean` | `true` | Giữ popover mở khi chuột di ra ngoài vùng content | `[ignoreHiddenPopoverContentWhenMouseLeave]="false"` |
331
+ | `[items]` | `Array<any>` | **required** | Danh sách items hiển thị trong menu | `[items]="options"` |
332
+ | `[keyField]` | `string` | `'key'` | Tên field trong object item dùng làm giá trị key định danh | `keyField="id"` |
333
+ | `[(keySelected)]` | `string` | `undefined` | Key của item đang được chọn — hỗ trợ two-way binding | `[(keySelected)]="selectedKey"` |
334
+ | `[label]` | `string` | `undefined` | Label mặc định của button (khi chưa chọn item nào, hoặc ở chế độ `applyNow=true`) | `label="Chọn trạng thái"` |
335
+ | `[modePopover]` | `TYPE_POPOVER_MODE` | `'click-toggle'` | Chế độ kích hoạt popover | `modePopover="click-toggle"` |
336
+ | `[popupConfig]` | `IPopupConfigButtonDropdown` | `{ width: 205, maxWidth: 250, maxHeight: 140, zIndex: 1200, direction: 'top' }` | Cấu hình chi tiết cho popover (kích thước, vị trí, z-index) | `[popupConfig]="myConfig"` |
337
+ | `[showBorderBottom]` | `boolean` | `false` | Hiển thị đường kẻ phân cách dưới mỗi item trong menu | `[showBorderBottom]="true"` |
338
+ | `[sizeButton]` | `TYPE_SIZE_BUTTON` | `'medium'` | Kích thước button | `sizeButton="small"` |
339
+ | `[typeButton]` | `TYPE_BUTTON` | `'button-primary'` | Kiểu button (màu sắc, style) | `typeButton="button-secondary"` |
340
+
341
+ ## @Output()
342
+
343
+ | Output | Type | Mô tả | Handler TS | Binding HTML |
344
+ |---|---|---|---|---|
345
+ | `(outApply)` | `any` | Emit item được chọn khi bấm nút Apply (chỉ ở chế độ `applyNow = false`) | `handlerApply(event: Event, item: any): void { event.stopPropagation(); console.log(item); }` | `(outApply)="handlerApply($event, $event)"` |
346
+ | `(outFunctionsControl)` | `IPopoverFunctionControlEvent` | Emit object chứa các hàm điều khiển popover (show, hide) ngay sau khi popover khởi tạo | `handlerFunctionsControl(event: Event, ctrl: IPopoverFunctionControlEvent): void { event.stopPropagation(); }` | `(outFunctionsControl)="handlerFunctionsControl($event, $event)"` |
347
+ | `(outHover)` | `boolean` | Emit `false` mỗi khi user vừa chọn xong một item | `handlerHover(event: Event, state: boolean): void { event.stopPropagation(); }` | `(outHover)="handlerHover($event, $event)"` |
348
+ | `(outIconEvent)` | `MouseEvent` | Emit MouseEvent khi click vào icon của button | `handlerIconClick(event: MouseEvent): void { event.stopPropagation(); }` | `(outIconEvent)="handlerIconClick($event)"` |
349
+ | `(outPopoverEvent)` | `TYPE_POPOVER_EVENT` | Emit các sự kiện lifecycle của popover (open, close, ...) | `handlerPopoverEvent(event: Event, evt: TYPE_POPOVER_EVENT): void { event.stopPropagation(); }` | `(outPopoverEvent)="handlerPopoverEvent($event, $event)"` |
350
+ | `(outSelectItem)` | `any` | Emit object item khi user click chọn một mục trong menu | `handlerSelectItem(event: Event, item: any): void { event.stopPropagation(); console.log(item); }` | `(outSelectItem)="handlerSelectItem($event, $event)"` |
351
+
352
+ ## Public API FunctionsControl
353
+
354
+ Truy cập qua `viewChild` để điều khiển popover từ component cha:
355
+
356
+ ```typescript
357
+ import { Component, viewChild } from '@angular/core';
358
+ import {
359
+ LibsUiComponentsButtonsDropdownComponent,
360
+ IButtonDropdown,
361
+ } from '@libs-ui/components-buttons-dropdown';
362
+ import { IPopoverFunctionControlEvent } from '@libs-ui/components-popover';
363
+
364
+ @Component({
365
+ selector: 'app-demo',
366
+ standalone: true,
367
+ imports: [LibsUiComponentsButtonsDropdownComponent],
368
+ template: `
369
+ <libs_ui-components-buttons-dropdown
370
+ #myDropdown
371
+ label="Menu"
372
+ [items]="items"
373
+ [applyNow]="true"
374
+ (outFunctionsControl)="handlerControl($event)" />
375
+ `,
376
+ })
377
+ export class DemoComponent {
378
+ private readonly dropdownRef = viewChild<LibsUiComponentsButtonsDropdownComponent>('myDropdown');
379
+
380
+ protected items = [
381
+ { key: '1', label: 'Mục 1' },
382
+ { key: '2', label: 'Mục 2' },
383
+ ];
384
+
385
+ handlerControl(ctrl: IPopoverFunctionControlEvent): void {
386
+ // ctrl được lưu bên trong component — gọi show/hide từ bên ngoài
387
+ }
388
+
389
+ // Mở popup từ bên ngoài
390
+ openMenu(): void {
391
+ this.dropdownRef()?.FunctionsControl?.show?.();
392
+ }
393
+
394
+ // Đóng popup từ bên ngoài
395
+ closeMenu(): void {
396
+ this.dropdownRef()?.FunctionsControl?.hide?.();
397
+ }
398
+ }
399
+ ```
400
+
401
+ | Getter | Return Type | Mô tả |
402
+ |---|---|---|
403
+ | `FunctionsControl` | `IPopoverFunctionControlEvent \| undefined` | Trả về object chứa các hàm điều khiển popover. `undefined` nếu popover chưa khởi tạo |
404
+
405
+ ## Cấu trúc Item
406
+
407
+ Mỗi phần tử trong mảng `items` hỗ trợ các thuộc tính sau:
408
+
409
+ ```typescript
410
+ interface DropdownItem {
411
+ // Bắt buộc (tên field tùy theo fieldDisplay và keyField)
412
+ label: string; // field hiển thị — mặc định key là 'label'
413
+ key: string; // field key định danh — mặc định key là 'key'
414
+
415
+ // Tùy chọn — styling
416
+ class?: string; // Class CSS cho span hiển thị label của item (ghi đè 'libs-ui-font-h5r')
417
+ classIconLeft?: string; // Class icon hiển thị bên trái label item
418
+ classInclude?: string; // Class CSS bổ sung cho div wrapper của item
419
+ classRow?: string; // Class CSS cho div row ngoài cùng của item
420
+
421
+ // Tùy chọn — behavior
422
+ disable?: boolean; // Disable item (pointer-events-none + visual disabled)
423
+ ignoreFlex?: boolean; // Bỏ display:flex cho wrapper item
424
+ showPopover?: boolean; // Hiển thị tooltip/popover riêng cho item này
425
+ popoverContent?: string; // Nội dung tooltip khi showPopover = true
426
+
427
+ // Tùy chọn — advanced
428
+ subTemplate?: TemplateRef<unknown>; // Custom Angular template render bên trong item
429
+ buttonTemplateConfig?: { // Render thêm một button bên trong item
430
+ icon?: string; // Class icon bên phải button
431
+ iconLeft?: string; // Class icon bên trái button
432
+ label?: string; // Label của button
433
+ type?: TYPE_BUTTON; // Kiểu button
434
+ action: (item: DropdownItem, allItems: DropdownItem[]) => void; // Callback khi click
435
+ };
436
+ }
437
+ ```
219
438
 
220
439
  ## Types & Interfaces
221
440
 
222
441
  ```typescript
223
- /**
224
- * Interface cho Dropdown Button component
225
- */
442
+ import {
443
+ IButtonDropdown,
444
+ IPopupConfigButtonDropdown,
445
+ } from '@libs-ui/components-buttons-dropdown';
446
+ ```
447
+
448
+ ```typescript
449
+ // IButtonDropdown — kế thừa IButton, mô tả đầy đủ inputs của component
226
450
  export interface IButtonDropdown extends IButton {
227
- /** Danh sách các mục sẽ hiển thị trong menu */
228
451
  items: any[];
229
- /** Tên trường dùng để hiển thị nội dung của mỗi mục */
230
452
  fieldDisplay?: string;
231
- /** Tên trường dùng làm giá trị key của mỗi mục */
232
453
  keyField?: string;
233
- /** Giá trị key đang được chọn (hỗ trợ two-way binding) */
234
454
  keySelected?: string;
235
- /** Nếu true: chọn xong tự emit sự kiện; false: cần bấm nút Áp dụng */
236
455
  applyNow?: boolean;
237
- /** Hiển thị đường kẻ dưới menu khi mở */
238
456
  showBorderBottom?: boolean;
239
- /** Cấu hình chi tiết cho popover (vị trí, kích thước) */
240
457
  popupConfig?: IPopupConfigButtonDropdown;
241
- /** Giữ popover mở khi chuột rời khỏi nội dung */
242
458
  ignoreHiddenPopoverContentWhenMouseLeave?: boolean;
243
- /** Cách hiển thị popover (click, hover,...) */
244
459
  modePopover?: TYPE_POPOVER_MODE;
245
460
  }
246
461
 
247
- /**
248
- * Cấu hình cho Dropdown popover
249
- */
462
+ // IPopupConfigButtonDropdown — cấu hình popover
250
463
  export interface IPopupConfigButtonDropdown {
251
- width?: number;
252
- maxWidth?: number;
253
- maxHeight?: number;
254
- zIndex?: number;
255
- direction?: TYPE_POPOVER_DIRECTION;
256
- timeDestroy?: number;
257
- widthByParent?: boolean;
464
+ width?: number; // Chiều rộng cố định (px)
465
+ maxWidth?: number; // Chiều rộng tối đa (px)
466
+ maxHeight?: number; // Chiều cao tối đa của danh sách (px)
467
+ zIndex?: number; // z-index của popover layer
468
+ direction?: TYPE_POPOVER_DIRECTION; // Hướng mở: 'top' | 'bottom' | 'left' | 'right'
469
+ timeDestroy?: number; // Thời gian (ms) trước khi DOM popover bị destroy sau khi đóng
470
+ widthByParent?: boolean; // Lấy chiều rộng theo parent element
258
471
  position?: {
259
- mode: 'start' | 'center' | 'end';
260
- distance: number;
472
+ mode: 'start' | 'center' | 'end'; // Căn lề ngang của popup so với trigger
473
+ distance: number; // Khoảng lệch theo chiều ngang (px)
261
474
  };
262
- classInclude?: string;
475
+ classInclude?: string; // Class CSS bổ sung cho container popover
263
476
  }
264
477
  ```
265
478
 
266
- ## Item Structure
479
+ ## Lưu ý quan trọng
267
480
 
268
- Mỗi item trong array `items` thểcác thuộc tính:
481
+ ⚠️ **`items` required**: Input `[items]` bắt buộc phải truyền vào. Truyền mảng rỗng `[]` để hiển thị trạng thái "Không dữ liệu".
269
482
 
270
- ```typescript
271
- interface DropdownItem {
272
- // Required fields (tùy theo fieldDisplay keyField)
273
- [fieldDisplay]: string; // Mặc định: 'label'
274
- [keyField]: string; // Mặc định: 'key'
275
-
276
- // Optional fields
277
- class?: string; // Class cho item
278
- classIconLeft?: string; // Icon class
279
- classInclude?: string; // Class bổ sung
280
- classRow?: string; // Class cho row
281
- disable?: boolean; // Disable item
282
- ignoreFlex?: boolean; // Không dùng flex layout
283
- showPopover?: boolean; // Hiển thị popover cho item
284
- popoverContent?: string; // Nội dung popover
285
- subTemplate?: TemplateRef; // Custom template
286
- buttonTemplateConfig?: {
287
- // Config cho button trong item
288
- icon?: string;
289
- iconLeft?: string;
290
- label?: string;
291
- type?: TYPE_BUTTON;
292
- action: (item: any, items: any[]) => void;
293
- };
294
- }
295
- ```
483
+ ⚠️ **`applyNow = false` yêu cầu `keyField`**: Khi dùng chế độ apply sau, component cần `keyField` để theo dõi item đang được chọn. Giá trị mặc định là `'key'` — đảm bảo mỗi item có field `key` hoặc truyền `keyField` phù hợp.
484
+
485
+ ⚠️ **Label button thay đổi khi `applyNow = false`**: Ở chế độ `applyNow = false`, sau khi user chọn item, label trên button chính sẽ tự động cập nhật sang tên item được chọn (dựa theo `fieldDisplay`). Để label cố định, dùng `applyNow = true`.
296
486
 
297
- ## Công nghệ
487
+ ⚠️ **XSS tự động**: Giá trị của field `fieldDisplay` trong từng item được tự động xử lý qua `escapeHtml` khi truyền vào component. Không cần escape thủ công trước khi truyền.
298
488
 
299
- | Technology | Version | Purpose |
300
- | --------------- | ------- | ---------------- |
301
- | Angular | 18+ | Framework |
302
- | Angular Signals | - | State management |
303
- | TailwindCSS | 3.x | Styling |
304
- | OnPush | - | Change Detection |
489
+ ⚠️ **`FunctionsControl` thể `undefined`**: Getter `FunctionsControl` trả về `undefined` nếu popover chưa được mount. Luôn kiểm tra `?.` trước khi gọi các method bên trong.
305
490
 
306
491
  ## Demo
307
492
 
@@ -310,20 +495,3 @@ npx nx serve core-ui
310
495
  ```
311
496
 
312
497
  Truy cập: `http://localhost:4500/buttons/dropdown`
313
-
314
- ## Unit Tests
315
-
316
- ```bash
317
- # Chạy tests
318
- npx nx test components-buttons-dropdown
319
-
320
- # Coverage
321
- npx nx test components-buttons-dropdown --coverage
322
-
323
- # Watch mode
324
- npx nx test components-buttons-dropdown --watch
325
- ```
326
-
327
- ## License
328
-
329
- MIT
@@ -1,6 +1,6 @@
1
1
  import { NgTemplateOutlet } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
- import { signal, computed, input, model, output, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { signal, computed, input, model, output, Component, ChangeDetectionStrategy } from '@angular/core';
4
4
  import { LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';
5
5
  import { LibsUiComponentsPopoverComponent } from '@libs-ui/components-popover';
6
6
  import { escapeHtml } from '@libs-ui/utils';
@@ -1 +1 @@
1
- {"version":3,"file":"libs-ui-components-buttons-dropdown.mjs","sources":["../../../../../../libs-ui/components/buttons/dropdown/src/dropdown.component.ts","../../../../../../libs-ui/components/buttons/dropdown/src/dropdown.component.html","../../../../../../libs-ui/components/buttons/dropdown/src/libs-ui-components-buttons-dropdown.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed, input, model, output, signal } from '@angular/core';\nimport { LibsUiComponentsButtonsButtonComponent, TYPE_BUTTON, TYPE_SIZE_BUTTON } from '@libs-ui/components-buttons-button';\nimport { IPopoverFunctionControlEvent, LibsUiComponentsPopoverComponent, TYPE_POPOVER_EVENT, TYPE_POPOVER_MODE } from '@libs-ui/components-popover';\nimport { escapeHtml } from '@libs-ui/utils';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { IPopupConfigButtonDropdown } from './dropdown.interface';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-buttons-dropdown',\n templateUrl: './dropdown.component.html',\n styleUrl: './dropdown.component.scss',\n standalone: true,\n imports: [TranslateModule, NgTemplateOutlet, LibsUiComponentsButtonsButtonComponent, LibsUiComponentsPopoverComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class LibsUiComponentsButtonsDropdownComponent {\n // #region PROPERTY\n private readonly functionsControlPopover = signal<IPopoverFunctionControlEvent | undefined>(undefined);\n protected labelDisplay = computed(this.labelComputed.bind(this));\n\n // #region INPUT\n readonly label = input<string>();\n readonly fieldClass = input<string>('class'); // change color label item of items\n readonly fieldClassIconLeft = input<string>('classIconLeft'); // iconclass item of items\n readonly items = input.required<Array<any>, Array<any>>({ transform: (data) => data.map((item) => ({ ...item, [this.fieldDisplay()]: escapeHtml(item[this.fieldDisplay()]) })) }); // requried\n readonly fieldDisplay = input<string, string | undefined>('label', { transform: (value) => value ?? 'label' });\n readonly keyField = input<string, string | undefined>('key', { transform: (value) => value ?? 'key' });\n readonly keySelected = model<string>();\n readonly applyNow = input<boolean>(false); // if not applyNow: keyField is requried\n readonly showBorderBottom = input<boolean>(false);\n readonly disable = input<boolean>(false);\n readonly sizeButton = input<TYPE_SIZE_BUTTON>('medium');\n readonly classLabel = input<string>('');\n readonly iconOnlyType = input<boolean>(false);\n readonly classIconRight = input<string>('libs-ui-icon-move-right rotate-[90deg]');\n readonly classIconLeft = input<string>('');\n readonly typeButton = input<TYPE_BUTTON>('button-primary');\n readonly popupConfig = input<IPopupConfigButtonDropdown>({ width: 205, maxWidth: 250, maxHeight: 140, zIndex: 1200, direction: 'top' });\n readonly ignoreHiddenPopoverContentWhenMouseLeave = input<boolean>(true);\n readonly classInclude = input<string>('');\n readonly modePopover = input<TYPE_POPOVER_MODE>('click-toggle');\n readonly classIncludeContainer = input<string>();\n\n // #region OUTPUT\n readonly outSelectItem = output<any>();\n readonly outHover = output<boolean>();\n readonly outApply = output<any>(); // sử dụng cho bấm button left chế độ applyNow = false;\n readonly outPopoverEvent = output<TYPE_POPOVER_EVENT>();\n readonly outFunctionsControl = output<IPopoverFunctionControlEvent>();\n readonly outIconEvent = output<MouseEvent>();\n\n /* FUNCTIONS */\n protected async handlerApply() {\n if (!this.applyNow()) {\n this.outApply.emit(this.items().find((item) => item[this.keyField()] === this.keySelected()));\n }\n }\n\n protected async handlerSelectItem(event: Event, data: any) {\n event.stopPropagation();\n if (data.subTemplate) {\n return;\n }\n if (!this.applyNow()) {\n this.keySelected.set(data[this.keyField()]);\n }\n this.outSelectItem.emit(data);\n this.outHover.emit(false);\n }\n\n protected async handlerPopoverEvent(event: TYPE_POPOVER_EVENT) {\n this.outPopoverEvent.emit(event);\n }\n\n protected async handlerPopoverControlEvent(control: IPopoverFunctionControlEvent) {\n this.outFunctionsControl.emit(control);\n this.functionsControlPopover.set(control);\n }\n\n public get FunctionsControl(): IPopoverFunctionControlEvent | undefined {\n return this.functionsControlPopover();\n }\n\n protected async handlerClickButtonTemplate(event: Event, data: any, items: Array<any>) {\n event.stopPropagation();\n data.buttonTemplateConfig.action(data, items);\n }\n\n private labelComputed() {\n if (!this.keySelected() || !this.items()?.length || !this.keyField() || this.applyNow()) {\n return this.label();\n }\n for (const item of this.items()) {\n if (item[this.keyField()] === this.keySelected()) {\n return item[this.fieldDisplay()];\n }\n }\n\n return this.label();\n }\n}\n","<div\n #buttonDropdownEl\n class=\"libs-ui-buttons-dropdown flex {{ classIncludeContainer() || '' }}\"\n [class.libs-ui-buttons-dropdown-un-apply-now]=\"!applyNow()\"\n [class.libs-ui-buttons-dropdown-apply-now-button-primary]=\"applyNow() && typeButton() === 'button-primary'\"\n [class.libs-ui-buttons-dropdown-apply-now-button-secondary]=\"applyNow() && typeButton() === 'button-secondary'\">\n <libs_ui-components-buttons-button\n [disable]=\"disable()\"\n [iconOnlyType]=\"iconOnlyType()\"\n [classIconLeft]=\"classIconLeft()\"\n [classIconRight]=\"!applyNow() ? '' : classIconRight()\"\n [type]=\"typeButton()\"\n [classLabel]=\"classLabel()\"\n [classInclude]=\"classInclude()\"\n [sizeButton]=\"sizeButton()\"\n [popover]=\"{\n elementRefCustom: buttonDropdownEl,\n mode: modePopover(),\n ignoreShowPopover: !applyNow(),\n ignoreHiddenPopoverContentWhenMouseLeave: true,\n config: {\n animationConfig: {\n time: 0.5,\n },\n template: templateContentEl,\n whiteTheme: true,\n ignoreArrow: true,\n width: popupConfig().width,\n widthByParent: popupConfig().widthByParent ?? false,\n maxWidth: popupConfig().maxWidth,\n maxHeight: popupConfig().maxHeight,\n zIndex: popupConfig().zIndex,\n classInclude: 'rounded-[4px] ' + popupConfig().classInclude,\n direction: popupConfig().direction,\n timerDestroy: popupConfig().timeDestroy,\n directionDistance: 2,\n position: {\n mode: popupConfig().position?.mode || 'start',\n distance: popupConfig().position?.distance ?? 0,\n },\n },\n }\"\n [label]=\"labelDisplay()\"\n (outFunctionsControl)=\"handlerPopoverControlEvent($event)\"\n (outPopoverEvent)=\"handlerPopoverEvent($event)\"\n (outClick)=\"handlerApply()\" />\n @if (!applyNow()) {\n <div class=\"h-full w-[1px] bg-white\"></div>\n <libs_ui-components-buttons-button\n [type]=\"typeButton()\"\n [disable]=\"disable()\"\n [sizeButton]=\"sizeButton()\"\n [popover]=\"{\n mode: 'click-toggle',\n ignoreHiddenPopoverContentWhenMouseLeave: ignoreHiddenPopoverContentWhenMouseLeave(),\n config: {\n animationConfig: {\n time: 0.5,\n },\n template: templateContentEl,\n whiteTheme: true,\n ignoreArrow: true,\n width: popupConfig().width,\n maxWidth: popupConfig().maxWidth,\n widthByParent: popupConfig().widthByParent ?? false,\n maxHeight: popupConfig().maxHeight,\n zIndex: popupConfig().zIndex,\n direction: popupConfig().direction,\n classInclude: popupConfig().classInclude,\n directionDistance: 2,\n position: {\n mode: 'start',\n distance: 0,\n },\n },\n }\"\n [iconOnlyType]=\"true\"\n [classIconRight]=\"classIconRight()\"\n [classInclude]=\"classInclude() || '!py-[9px]'\"\n (outFunctionsControl)=\"handlerPopoverControlEvent($event)\"\n (outPopoverEvent)=\"handlerPopoverEvent($event)\" />\n }\n</div>\n<ng-template #templateContentEl>\n <div>\n @if (items() && items().length) {\n <div class=\"m-0 p-0\">\n @for (item of items(); track item) {\n <div class=\"{{ item.classRow || '' }}\">\n <div\n LibsUiComponentsPopoverDirective\n [config]=\"{ content: item.popoverContent, zIndex: popupConfig().zIndex, directionDistance: -2 }\"\n [ignoreShowPopover]=\"!item.showPopover\"\n [ignoreStopPropagationEvent]=\"true\"\n class=\"libs-ui-bg-list-hover relative cursor-pointer py-[7px] {{ item.classInclude || '' }} {{ showBorderBottom() ? 'libs-ui-border-bottom-general' : '' }}\"\n tabindex=\"0\"\n [class.flex]=\"!item.ignoreFlex\"\n [class.px-[16px]]=\"applyNow()\"\n [class.pl-[16px]]=\"!applyNow()\"\n [class.pr-[40px]]=\"!applyNow()\"\n [class.libs-ui-disable]=\"item.disable\"\n [class.pointer-events-none]=\"item.disable\"\n (click)=\"handlerSelectItem($event, item)\"\n (keydown.enter)=\"handlerSelectItem($any($event), item)\"\n (keydown.space)=\"handlerSelectItem($any($event), item)\">\n @if (item[fieldClassIconLeft()]) {\n <i [class]=\"item[fieldClassIconLeft()]\"></i>\n }\n <span\n [class]=\"item[fieldClass()] ?? 'libs-ui-font-h5r'\"\n [innerHtml]=\"item[fieldDisplay()] | translate\"></span>\n @if (item.buttonTemplateConfig) {\n <libs_ui-components-buttons-button\n [classIconLeft]=\"item.buttonTemplateConfig.iconLeft\"\n [classIconRight]=\"item.buttonTemplateConfig.icon\"\n [label]=\"item.buttonTemplateConfig.label\"\n [classLabel]=\"item.buttonTemplateConfig.label\"\n (outClick)=\"handlerClickButtonTemplate($event, item, items())\"\n [type]=\"item.buttonTemplateConfig.type\" />\n }\n <ng-container *ngTemplateOutlet=\"item?.subTemplate || null; context: { item: item }\"></ng-container>\n @if (item[keyField()] === keySelected() && !applyNow()) {\n <i class=\"libs-ui-icon-check absolute right-[16px] top-[8px]\"></i>\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <div\n class=\"p-[20px]\"\n [innerHtml]=\"'i18n_no_data' | translate\"></div>\n }\n </div>\n</ng-template>\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-dropdown.mjs","sources":["../../../../../../libs-ui/components/buttons/dropdown/src/dropdown.component.ts","../../../../../../libs-ui/components/buttons/dropdown/src/dropdown.component.html","../../../../../../libs-ui/components/buttons/dropdown/src/libs-ui-components-buttons-dropdown.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed, input, model, output, signal } from '@angular/core';\nimport { LibsUiComponentsButtonsButtonComponent, TYPE_BUTTON, TYPE_SIZE_BUTTON } from '@libs-ui/components-buttons-button';\nimport { IPopoverFunctionControlEvent, LibsUiComponentsPopoverComponent, TYPE_POPOVER_EVENT, TYPE_POPOVER_MODE } from '@libs-ui/components-popover';\nimport { escapeHtml } from '@libs-ui/utils';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { IPopupConfigButtonDropdown } from './dropdown.interface';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-buttons-dropdown',\n templateUrl: './dropdown.component.html',\n styleUrl: './dropdown.component.scss',\n standalone: true,\n imports: [TranslateModule, NgTemplateOutlet, LibsUiComponentsButtonsButtonComponent, LibsUiComponentsPopoverComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class LibsUiComponentsButtonsDropdownComponent {\n // #region PROPERTY\n private readonly functionsControlPopover = signal<IPopoverFunctionControlEvent | undefined>(undefined);\n protected labelDisplay = computed(this.labelComputed.bind(this));\n\n // #region INPUT\n readonly label = input<string>();\n readonly fieldClass = input<string>('class'); // change color label item of items\n readonly fieldClassIconLeft = input<string>('classIconLeft'); // iconclass item of items\n readonly items = input.required<Array<any>, Array<any>>({ transform: (data) => data.map((item) => ({ ...item, [this.fieldDisplay()]: escapeHtml(item[this.fieldDisplay()]) })) }); // requried\n readonly fieldDisplay = input<string, string | undefined>('label', { transform: (value) => value ?? 'label' });\n readonly keyField = input<string, string | undefined>('key', { transform: (value) => value ?? 'key' });\n readonly keySelected = model<string>();\n readonly applyNow = input<boolean>(false); // if not applyNow: keyField is requried\n readonly showBorderBottom = input<boolean>(false);\n readonly disable = input<boolean>(false);\n readonly sizeButton = input<TYPE_SIZE_BUTTON>('medium');\n readonly classLabel = input<string>('');\n readonly iconOnlyType = input<boolean>(false);\n readonly classIconRight = input<string>('libs-ui-icon-move-right rotate-[90deg]');\n readonly classIconLeft = input<string>('');\n readonly typeButton = input<TYPE_BUTTON>('button-primary');\n readonly popupConfig = input<IPopupConfigButtonDropdown>({ width: 205, maxWidth: 250, maxHeight: 140, zIndex: 1200, direction: 'top' });\n readonly ignoreHiddenPopoverContentWhenMouseLeave = input<boolean>(true);\n readonly classInclude = input<string>('');\n readonly modePopover = input<TYPE_POPOVER_MODE>('click-toggle');\n readonly classIncludeContainer = input<string>();\n\n // #region OUTPUT\n readonly outSelectItem = output<any>();\n readonly outHover = output<boolean>();\n readonly outApply = output<any>(); // sử dụng cho bấm button left chế độ applyNow = false;\n readonly outPopoverEvent = output<TYPE_POPOVER_EVENT>();\n readonly outFunctionsControl = output<IPopoverFunctionControlEvent>();\n readonly outIconEvent = output<MouseEvent>();\n\n /* FUNCTIONS */\n protected async handlerApply() {\n if (!this.applyNow()) {\n this.outApply.emit(this.items().find((item) => item[this.keyField()] === this.keySelected()));\n }\n }\n\n protected async handlerSelectItem(event: Event, data: any) {\n event.stopPropagation();\n if (data.subTemplate) {\n return;\n }\n if (!this.applyNow()) {\n this.keySelected.set(data[this.keyField()]);\n }\n this.outSelectItem.emit(data);\n this.outHover.emit(false);\n }\n\n protected async handlerPopoverEvent(event: TYPE_POPOVER_EVENT) {\n this.outPopoverEvent.emit(event);\n }\n\n protected async handlerPopoverControlEvent(control: IPopoverFunctionControlEvent) {\n this.outFunctionsControl.emit(control);\n this.functionsControlPopover.set(control);\n }\n\n public get FunctionsControl(): IPopoverFunctionControlEvent | undefined {\n return this.functionsControlPopover();\n }\n\n protected async handlerClickButtonTemplate(event: Event, data: any, items: Array<any>) {\n event.stopPropagation();\n data.buttonTemplateConfig.action(data, items);\n }\n\n private labelComputed() {\n if (!this.keySelected() || !this.items()?.length || !this.keyField() || this.applyNow()) {\n return this.label();\n }\n for (const item of this.items()) {\n if (item[this.keyField()] === this.keySelected()) {\n return item[this.fieldDisplay()];\n }\n }\n\n return this.label();\n }\n}\n","<div\n #buttonDropdownEl\n class=\"libs-ui-buttons-dropdown flex {{ classIncludeContainer() || '' }}\"\n [class.libs-ui-buttons-dropdown-un-apply-now]=\"!applyNow()\"\n [class.libs-ui-buttons-dropdown-apply-now-button-primary]=\"applyNow() && typeButton() === 'button-primary'\"\n [class.libs-ui-buttons-dropdown-apply-now-button-secondary]=\"applyNow() && typeButton() === 'button-secondary'\">\n <libs_ui-components-buttons-button\n [disable]=\"disable()\"\n [iconOnlyType]=\"iconOnlyType()\"\n [classIconLeft]=\"classIconLeft()\"\n [classIconRight]=\"!applyNow() ? '' : classIconRight()\"\n [type]=\"typeButton()\"\n [classLabel]=\"classLabel()\"\n [classInclude]=\"classInclude()\"\n [sizeButton]=\"sizeButton()\"\n [popover]=\"{\n elementRefCustom: buttonDropdownEl,\n mode: modePopover(),\n ignoreShowPopover: !applyNow(),\n ignoreHiddenPopoverContentWhenMouseLeave: true,\n config: {\n animationConfig: {\n time: 0.5,\n },\n template: templateContentEl,\n whiteTheme: true,\n ignoreArrow: true,\n width: popupConfig().width,\n widthByParent: popupConfig().widthByParent ?? false,\n maxWidth: popupConfig().maxWidth,\n maxHeight: popupConfig().maxHeight,\n zIndex: popupConfig().zIndex,\n classInclude: 'rounded-[4px] ' + popupConfig().classInclude,\n direction: popupConfig().direction,\n timerDestroy: popupConfig().timeDestroy,\n directionDistance: 2,\n position: {\n mode: popupConfig().position?.mode || 'start',\n distance: popupConfig().position?.distance ?? 0,\n },\n },\n }\"\n [label]=\"labelDisplay()\"\n (outFunctionsControl)=\"handlerPopoverControlEvent($event)\"\n (outPopoverEvent)=\"handlerPopoverEvent($event)\"\n (outClick)=\"handlerApply()\" />\n @if (!applyNow()) {\n <div class=\"h-full w-[1px] bg-white\"></div>\n <libs_ui-components-buttons-button\n [type]=\"typeButton()\"\n [disable]=\"disable()\"\n [sizeButton]=\"sizeButton()\"\n [popover]=\"{\n mode: 'click-toggle',\n ignoreHiddenPopoverContentWhenMouseLeave: ignoreHiddenPopoverContentWhenMouseLeave(),\n config: {\n animationConfig: {\n time: 0.5,\n },\n template: templateContentEl,\n whiteTheme: true,\n ignoreArrow: true,\n width: popupConfig().width,\n maxWidth: popupConfig().maxWidth,\n widthByParent: popupConfig().widthByParent ?? false,\n maxHeight: popupConfig().maxHeight,\n zIndex: popupConfig().zIndex,\n direction: popupConfig().direction,\n classInclude: popupConfig().classInclude,\n directionDistance: 2,\n position: {\n mode: 'start',\n distance: 0,\n },\n },\n }\"\n [iconOnlyType]=\"true\"\n [classIconRight]=\"classIconRight()\"\n [classInclude]=\"classInclude() || '!py-[9px]'\"\n (outFunctionsControl)=\"handlerPopoverControlEvent($event)\"\n (outPopoverEvent)=\"handlerPopoverEvent($event)\" />\n }\n</div>\n<ng-template #templateContentEl>\n <div>\n @if (items() && items().length) {\n <div class=\"m-0 p-0\">\n @for (item of items(); track item) {\n <div class=\"{{ item.classRow || '' }}\">\n <div\n LibsUiComponentsPopoverDirective\n [config]=\"{ content: item.popoverContent, zIndex: popupConfig().zIndex, directionDistance: -2 }\"\n [ignoreShowPopover]=\"!item.showPopover\"\n [ignoreStopPropagationEvent]=\"true\"\n class=\"libs-ui-bg-list-hover relative cursor-pointer py-[7px] {{ item.classInclude || '' }} {{ showBorderBottom() ? 'libs-ui-border-bottom-general' : '' }}\"\n tabindex=\"0\"\n [class.flex]=\"!item.ignoreFlex\"\n [class.px-[16px]]=\"applyNow()\"\n [class.pl-[16px]]=\"!applyNow()\"\n [class.pr-[40px]]=\"!applyNow()\"\n [class.libs-ui-disable]=\"item.disable\"\n [class.pointer-events-none]=\"item.disable\"\n (click)=\"handlerSelectItem($event, item)\"\n (keydown.enter)=\"handlerSelectItem($any($event), item)\"\n (keydown.space)=\"handlerSelectItem($any($event), item)\">\n @if (item[fieldClassIconLeft()]) {\n <i [class]=\"item[fieldClassIconLeft()]\"></i>\n }\n <span\n [class]=\"item[fieldClass()] ?? 'libs-ui-font-h5r'\"\n [innerHtml]=\"item[fieldDisplay()] | translate\"></span>\n @if (item.buttonTemplateConfig) {\n <libs_ui-components-buttons-button\n [classIconLeft]=\"item.buttonTemplateConfig.iconLeft\"\n [classIconRight]=\"item.buttonTemplateConfig.icon\"\n [label]=\"item.buttonTemplateConfig.label\"\n [classLabel]=\"item.buttonTemplateConfig.label\"\n (outClick)=\"handlerClickButtonTemplate($event, item, items())\"\n [type]=\"item.buttonTemplateConfig.type\" />\n }\n <ng-container *ngTemplateOutlet=\"item?.subTemplate || null; context: { item: item }\"></ng-container>\n @if (item[keyField()] === keySelected() && !applyNow()) {\n <i class=\"libs-ui-icon-check absolute right-[16px] top-[8px]\"></i>\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <div\n class=\"p-[20px]\"\n [innerHtml]=\"'i18n_no_data' | translate\"></div>\n }\n </div>\n</ng-template>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;;AAAA;MAkBa,wCAAwC,CAAA;;AAElC,IAAA,uBAAuB,GAAG,MAAM,CAA2C,SAAS,CAAC,CAAC;AAC7F,IAAA,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;;IAGxD,KAAK,GAAG,KAAK,EAAU,CAAC;AACxB,IAAA,UAAU,GAAG,KAAK,CAAS,OAAO,CAAC,CAAC;AACpC,IAAA,kBAAkB,GAAG,KAAK,CAAS,eAAe,CAAC,CAAC;IACpD,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAyB,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AACzK,IAAA,YAAY,GAAG,KAAK,CAA6B,OAAO,EAAE,EAAE,SAAS,EAAE,CAAC,KAAK,KAAK,KAAK,IAAI,OAAO,EAAE,CAAC,CAAC;AACtG,IAAA,QAAQ,GAAG,KAAK,CAA6B,KAAK,EAAE,EAAE,SAAS,EAAE,CAAC,KAAK,KAAK,KAAK,IAAI,KAAK,EAAE,CAAC,CAAC;IAC9F,WAAW,GAAG,KAAK,EAAU,CAAC;AAC9B,IAAA,QAAQ,GAAG,KAAK,CAAU,KAAK,CAAC,CAAC;AACjC,IAAA,gBAAgB,GAAG,KAAK,CAAU,KAAK,CAAC,CAAC;AACzC,IAAA,OAAO,GAAG,KAAK,CAAU,KAAK,CAAC,CAAC;AAChC,IAAA,UAAU,GAAG,KAAK,CAAmB,QAAQ,CAAC,CAAC;AAC/C,IAAA,UAAU,GAAG,KAAK,CAAS,EAAE,CAAC,CAAC;AAC/B,IAAA,YAAY,GAAG,KAAK,CAAU,KAAK,CAAC,CAAC;AACrC,IAAA,cAAc,GAAG,KAAK,CAAS,wCAAwC,CAAC,CAAC;AACzE,IAAA,aAAa,GAAG,KAAK,CAAS,EAAE,CAAC,CAAC;AAClC,IAAA,UAAU,GAAG,KAAK,CAAc,gBAAgB,CAAC,CAAC;IAClD,WAAW,GAAG,KAAK,CAA6B,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;AAC/H,IAAA,wCAAwC,GAAG,KAAK,CAAU,IAAI,CAAC,CAAC;AAChE,IAAA,YAAY,GAAG,KAAK,CAAS,EAAE,CAAC,CAAC;AACjC,IAAA,WAAW,GAAG,KAAK,CAAoB,cAAc,CAAC,CAAC;IACvD,qBAAqB,GAAG,KAAK,EAAU,CAAC;;IAGxC,aAAa,GAAG,MAAM,EAAO,CAAC;IAC9B,QAAQ,GAAG,MAAM,EAAW,CAAC;AAC7B,IAAA,QAAQ,GAAG,MAAM,EAAO,CAAC;IACzB,eAAe,GAAG,MAAM,EAAsB,CAAC;IAC/C,mBAAmB,GAAG,MAAM,EAAgC,CAAC;IAC7D,YAAY,GAAG,MAAM,EAAc,CAAC;;AAGnC,IAAA,MAAM,YAAY,GAAA;AAC1B,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE;AACpB,YAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;SAC/F;KACF;AAES,IAAA,MAAM,iBAAiB,CAAC,KAAY,EAAE,IAAS,EAAA;QACvD,KAAK,CAAC,eAAe,EAAE,CAAC;AACxB,QAAA,IAAI,IAAI,CAAC,WAAW,EAAE;YACpB,OAAO;SACR;AACD,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE;AACpB,YAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;SAC7C;AACD,QAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC9B,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;KAC3B;IAES,MAAM,mBAAmB,CAAC,KAAyB,EAAA;AAC3D,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;KAClC;IAES,MAAM,0BAA0B,CAAC,OAAqC,EAAA;AAC9E,QAAA,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACvC,QAAA,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;KAC3C;AAED,IAAA,IAAW,gBAAgB,GAAA;AACzB,QAAA,OAAO,IAAI,CAAC,uBAAuB,EAAE,CAAC;KACvC;AAES,IAAA,MAAM,0BAA0B,CAAC,KAAY,EAAE,IAAS,EAAE,KAAiB,EAAA;QACnF,KAAK,CAAC,eAAe,EAAE,CAAC;QACxB,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;KAC/C;IAEO,aAAa,GAAA;QACnB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;AACvF,YAAA,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;SACrB;QACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,EAAE;AAC/B,YAAA,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI,CAAC,WAAW,EAAE,EAAE;AAChD,gBAAA,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;aAClC;SACF;AAED,QAAA,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;KACrB;wGApFU,wCAAwC,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;4FAAxC,wCAAwC,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,qCAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,kBAAA,EAAA,EAAA,iBAAA,EAAA,oBAAA,EAAA,UAAA,EAAA,oBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,gBAAA,EAAA,EAAA,iBAAA,EAAA,kBAAA,EAAA,UAAA,EAAA,kBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,wCAAA,EAAA,EAAA,iBAAA,EAAA,0CAAA,EAAA,UAAA,EAAA,0CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,qBAAA,EAAA,EAAA,iBAAA,EAAA,uBAAA,EAAA,UAAA,EAAA,uBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,WAAA,EAAA,mBAAA,EAAA,aAAA,EAAA,eAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,UAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,qBAAA,EAAA,YAAA,EAAA,cAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EClBrD,8nLAuIA,EDxHY,MAAA,EAAA,CAAA,2wEAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,eAAe,4FAAE,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,sCAAsC,EAAA,QAAA,EAAA,mCAAA,EAAA,MAAA,EAAA,CAAA,WAAA,EAAA,MAAA,EAAA,cAAA,EAAA,YAAA,EAAA,OAAA,EAAA,SAAA,EAAA,WAAA,EAAA,WAAA,EAAA,cAAA,EAAA,eAAA,EAAA,gBAAA,EAAA,YAAA,EAAA,cAAA,EAAA,SAAA,EAAA,4BAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,eAAA,EAAA,aAAA,EAAA,yBAAA,EAAA,+BAAA,EAAA,oBAAA,EAAA,UAAA,EAAA,mCAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,EAAA,iBAAA,EAAA,qBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,gCAAgC,EAAA,QAAA,EAAA,+DAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,WAAA,EAAA,MAAA,EAAA,MAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,kBAAA,EAAA,6BAAA,EAAA,cAAA,EAAA,0CAAA,EAAA,4BAAA,EAAA,kCAAA,EAAA,8BAAA,EAAA,oBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,EAAA,wBAAA,EAAA,wBAAA,EAAA,qBAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAG1G,wCAAwC,EAAA,UAAA,EAAA,CAAA;kBATpD,SAAS;AAEE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,qCAAqC,EAGnC,UAAA,EAAA,IAAI,EACP,OAAA,EAAA,CAAC,eAAe,EAAE,gBAAgB,EAAE,sCAAsC,EAAE,gCAAgC,CAAC,EACrG,eAAA,EAAA,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,8nLAAA,EAAA,MAAA,EAAA,CAAA,2wEAAA,CAAA,EAAA,CAAA;;;AEhBjD;;AAEG;;;;"}
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@libs-ui/components-buttons-dropdown",
3
- "version": "0.2.356-42",
3
+ "version": "0.2.356-43",
4
4
  "peerDependencies": {
5
5
  "@angular/common": ">=18.0.0",
6
6
  "@angular/core": ">=18.0.0",
7
- "@libs-ui/components-buttons-button": "0.2.356-42",
8
- "@libs-ui/components-popover": "0.2.356-42",
9
- "@libs-ui/utils": "0.2.356-42",
7
+ "@libs-ui/components-buttons-button": "0.2.356-43",
8
+ "@libs-ui/components-popover": "0.2.356-43",
9
+ "@libs-ui/utils": "0.2.356-43",
10
10
  "@ngx-translate/core": "^15.0.0"
11
11
  },
12
12
  "sideEffects": false,