@libs-ui/components-pages-template-detail 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,132 +1,544 @@
1
1
  # @libs-ui/components-pages-template-detail
2
2
 
3
- > Template trang chi tiết chuẩn UI Kit, tích hợp đầy đủ header, navigationcác action phổ biến.
3
+ > Template layout chuẩn cho trang chi tiết tích hợp header nút quay lại, tiêu đề, thanh action phía phải với nhiều loại control.
4
4
 
5
5
  ## Giới thiệu
6
6
 
7
- `LibsUiComponentsPagesTemplateDetailComponent` một standalone Angular component cung cấp khung layout cho các trang chi tiết. giúp chuẩn hóa giao diệntrải nghiệm người dùng (UX) cho các tác vụ như xem/sửa thông tin thực thể.
7
+ `@libs-ui/components-pages-template-detail` cung cấp hai component khung layout dành cho trang chi tiết (detail page): **V1** (`LibsUiComponentsPagesTemplateDetailComponent`) và **V2** (`LibsUiComponentsPagesTemplateDetailV2Component`). Cả hai đều bao gồm header chuẩn hóa với nút quay lại, tiêu đề có popover, vùng action bên phải hỗ trợ nhiều loại control (button, switch, dropdown, radio group, tooltip-button). V2 bổ sung khả năng lazy-load component vào vùng body qua `bodyConfig`, skeleton loading, và `ChangeDetectionStrategy.OnPush`.
8
8
 
9
- ### Tính năng
9
+ > ⚠️ **Deprecated**: `LibsUiComponentsPagesTemplateDetailComponent` (V1) đã bị deprecated. Ưu tiên sử dụng `LibsUiComponentsPagesTemplateDetailV2Component` (V2) cho mọi trang mới.
10
10
 
11
- - **Header chuẩn hóa**: Tích hợp nút quay lại, tiêu đề và mô tả.
12
- - ✅ **Actions linh hoạt**: Hỗ trợ nhiều loại nút (button, switch, dropdown, radio group) ở bên phải header.
13
- - ✅ **Layout tùy biến**: Hỗ trợ chia tỉ lệ header (24/52/24) cho các trang cần hiển thị thông tin giữa.
14
- - ✅ **Scroll Overlay**: Tích hợp sẵn directive xử cuộn nội dung mượt mà.
15
- - ✅ **Angular Signals**: Sử dụng các tính năng mới nhất của Angular 18 (Input, Model).
11
+ ## Tính năng
12
+
13
+ - ✅ **Header chuẩn hóa**: Nút quay lại (chevron icon), nhãn "Quay lại danh sách", tiêu đề với popover tooltip khi hover.
14
+ - ✅ **Thanh action phải linh hoạt**: Hỗ trợ `button`, `swicth`, `menu-dropdown`, `button-dropdown`, `radio-group`, `tooltip-button`, `tooltip`, `circle-and-number` trên cùng một thanh header.
15
+ - ✅ **Header tùy chỉnh tiêu đề phụ (header.content)**: V2 hỗ trợ dòng tiêu đề lớn phía trên dải header chính.
16
+ - ✅ **Chia tỉ lệ header 24/52/24**: Bật `isSplitHeaderRatio` để header chia đều ba vùng trái — giữa — phải.
17
+ - ✅ **Vùng body lazy-load (V2)**: Lazy load component vào body qua `bodyConfig.getComponentOutlet`, hiển thị skeleton khi chưa resolve.
18
+ - ✅ **Skeleton loading (V2)**: Skeleton tùy chỉnh hoàn toàn qua `bodyConfig.skeletonConfig`.
19
+ - ✅ **Scroll overlay**: Tích hợp sẵn `LibsUiComponentsScrollOverlayDirective`, emit event `outScroll` khi cuộn body.
20
+ - ✅ **FunctionControl API**: Expose `setStateDisable()` qua `outFunctionControl` để component cha điều khiển trạng thái disable từ bên ngoài.
21
+ - ✅ **XSS-safe**: Tiêu đề và mô tả tự động escape HTML qua `LibsUiPipesEscapeHtmlPipe`.
22
+ - ✅ **Angular Signals + OnPush (V2)**: Toàn bộ input dùng Signal API, V2 có `ChangeDetectionStrategy.OnPush`.
16
23
 
17
24
  ## Khi nào sử dụng
18
25
 
19
- - Khi xây dựng trang chi tiết cho một thực thể (ví dụ: Chi tiết khách hàng, Chi tiết đơn hàng).
20
- - Cần một header thống nhất có đầy đủ các nút chức năng (Lưu, Hủy, Thao tác khác).
21
- - Phù hợp cho các layout yêu cầu sự tập trung vào nội dung chính nhưng vẫn cần truy cập nhanh các hành động quản lý.
26
+ - Khi xây dựng trang chi tiết thực thể (Chi tiết khách hàng, Chi tiết đơn hàng, Chi tiết hợp đồng...).
27
+ - Cần header thống nhất có đầy đủ action: nút Lưu, nút Hủy, dropdown thao tác, switch trạng thái.
28
+ - Trang chi tiết body một component riêng cần lazy-load (dùng V2 + `bodyConfig`).
29
+ - Khi muốn hiển thị tiêu đề trang ở giữa header (ví dụ: tên record đang xem), dùng `isSplitHeaderRatio` + `configCenter`.
22
30
 
23
31
  ## Cài đặt
24
32
 
25
33
  ```bash
26
- # npm
27
34
  npm install @libs-ui/components-pages-template-detail
28
-
29
- # yarn
30
- yarn add @libs-ui/components-pages-template-detail
31
35
  ```
32
36
 
33
37
  ## Import
34
38
 
35
39
  ```typescript
40
+ // V2 (khuyến nghị cho code mới)
41
+ import { LibsUiComponentsPagesTemplateDetailV2Component } from '@libs-ui/components-pages-template-detail';
42
+
43
+ // V1 (deprecated — chỉ dùng khi maintain code cũ)
36
44
  import { LibsUiComponentsPagesTemplateDetailComponent } from '@libs-ui/components-pages-template-detail';
37
45
 
46
+ // Interfaces & Types
47
+ import {
48
+ IPagesTemplateDetailConfigTitle,
49
+ IPagesTemplateDetailConfigRight,
50
+ IPagesTemplateDetailConfigCenter,
51
+ IPageDetailFunctionControl,
52
+ IPageDetailV2BodyConfig,
53
+ IPageDetailV2SectionData,
54
+ } from '@libs-ui/components-pages-template-detail';
55
+ ```
56
+
57
+ ## Ví dụ sử dụng
58
+
59
+ ### Ví dụ 1 — Trang chi tiết cơ bản (V2)
60
+
61
+ ```typescript
62
+ // customer-detail.component.ts
63
+ import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
64
+ import { LibsUiComponentsPagesTemplateDetailV2Component } from '@libs-ui/components-pages-template-detail';
65
+ import { IPageDetailFunctionControl, IPagesTemplateDetailConfigRight } from '@libs-ui/components-pages-template-detail';
66
+
38
67
  @Component({
68
+ selector: 'app-customer-detail',
39
69
  standalone: true,
40
- imports: [LibsUiComponentsPagesTemplateDetailComponent],
41
- // ...
70
+ changeDetection: ChangeDetectionStrategy.OnPush,
71
+ imports: [LibsUiComponentsPagesTemplateDetailV2Component],
72
+ template: `
73
+ <libs_ui-components-pages_template-detail_v2
74
+ [configTitle]="{
75
+ config: { content: 'Nguyễn Văn An' },
76
+ isShowBackToListLabel: true
77
+ }"
78
+ [configRight]="configRight"
79
+ (outClose)="handlerClose($event)"
80
+ (outFunctionControl)="handlerFunctionControl($event)">
81
+ </libs_ui-components-pages_template-detail_v2>
82
+ `,
42
83
  })
43
- export class YourDetailComponent {}
84
+ export class CustomerDetailComponent {
85
+ protected configRight: IPagesTemplateDetailConfigRight[] = [
86
+ {
87
+ key: 'button',
88
+ configButton: {
89
+ label: 'Lưu thay đổi',
90
+ type: 'button-primary',
91
+ action: () => this.handlerSave(),
92
+ },
93
+ },
94
+ {
95
+ key: 'button',
96
+ configButton: {
97
+ label: 'Hủy',
98
+ type: 'button-secondary',
99
+ action: () => this.handlerCancel(),
100
+ },
101
+ },
102
+ ];
103
+
104
+ private functionControl?: IPageDetailFunctionControl;
105
+
106
+ protected handlerClose(event: Event): void {
107
+ event.stopPropagation();
108
+ // Navigate back to list
109
+ }
110
+
111
+ protected handlerFunctionControl(control: IPageDetailFunctionControl): void {
112
+ this.functionControl = control;
113
+ }
114
+
115
+ private handlerSave(): void {
116
+ // Save logic
117
+ }
118
+
119
+ private handlerCancel(): void {
120
+ // Cancel logic
121
+ }
122
+ }
44
123
  ```
45
124
 
46
- ## Ví dụ
125
+ ### Ví dụ 2 — Header chia 3 phần (24/52/24) với tiêu đề ở giữa
47
126
 
48
- ### Cấu hình cơ bản
127
+ ```typescript
128
+ // order-detail.component.ts
129
+ import { ChangeDetectionStrategy, Component } from '@angular/core';
130
+ import { LibsUiComponentsPagesTemplateDetailV2Component } from '@libs-ui/components-pages-template-detail';
131
+ import {
132
+ IPageDetailFunctionControl,
133
+ IPagesTemplateDetailConfigCenter,
134
+ IPagesTemplateDetailConfigRight,
135
+ } from '@libs-ui/components-pages-template-detail';
49
136
 
50
- ```html
51
- <libs_ui-components-pages_template-detail
52
- [configTitle]="{
53
- config: { content: 'Chi tiết khách hàng' },
54
- isShowBackToListLabel: true
55
- }"
56
- [configRight]="[
137
+ @Component({
138
+ selector: 'app-order-detail',
139
+ standalone: true,
140
+ changeDetection: ChangeDetectionStrategy.OnPush,
141
+ imports: [LibsUiComponentsPagesTemplateDetailV2Component],
142
+ template: `
143
+ <libs_ui-components-pages_template-detail_v2
144
+ [isSplitHeaderRatio]="true"
145
+ [configTitle]="{
146
+ config: { content: 'Mã đơn: #DH-2024-001' },
147
+ isShowBackToListLabel: true
148
+ }"
149
+ [configCenter]="configCenter"
150
+ [configRight]="configRight"
151
+ (outClose)="handlerClose($event)"
152
+ (outFunctionControl)="handlerFunctionControl($event)">
153
+ </libs_ui-components-pages_template-detail_v2>
154
+ `,
155
+ })
156
+ export class OrderDetailComponent {
157
+ protected configCenter: IPagesTemplateDetailConfigCenter = {
158
+ title: 'Chi tiết đơn hàng',
159
+ classIncludeTitle: 'uppercase libs-ui-font-h4s',
160
+ };
161
+
162
+ protected configRight: IPagesTemplateDetailConfigRight[] = [
163
+ {
164
+ key: 'swicth',
165
+ configSwicth: {
166
+ active: true,
167
+ action: async (event) => {
168
+ // Handle switch change
169
+ },
170
+ },
171
+ },
172
+ {
173
+ key: 'menu-dropdown',
174
+ configDropdown: {
175
+ listConfig: [
176
+ { key: 'export', label: 'Xuất PDF' },
177
+ { key: 'print', label: 'In đơn hàng' },
178
+ { key: 'delete', label: 'Xóa đơn hàng' },
179
+ ],
180
+ },
181
+ },
182
+ ];
183
+
184
+ protected handlerClose(event: Event): void {
185
+ event.stopPropagation();
186
+ // Navigate back
187
+ }
188
+
189
+ protected handlerFunctionControl(control: IPageDetailFunctionControl): void {
190
+ // Store function control for external use
191
+ }
192
+ }
193
+ ```
194
+
195
+ ### Ví dụ 3 — Lazy-load body component (V2 + bodyConfig)
196
+
197
+ ```typescript
198
+ // contract-detail.component.ts
199
+ import { ChangeDetectionStrategy, Component } from '@angular/core';
200
+ import { from, of } from 'rxjs';
201
+ import { LibsUiComponentsPagesTemplateDetailV2Component } from '@libs-ui/components-pages-template-detail';
202
+ import {
203
+ IPageDetailFunctionControl,
204
+ IPageDetailV2BodyConfig,
205
+ IPagesTemplateDetailConfigRight,
206
+ } from '@libs-ui/components-pages-template-detail';
207
+
208
+ @Component({
209
+ selector: 'app-contract-detail',
210
+ standalone: true,
211
+ changeDetection: ChangeDetectionStrategy.OnPush,
212
+ imports: [LibsUiComponentsPagesTemplateDetailV2Component],
213
+ template: `
214
+ <libs_ui-components-pages_template-detail_v2
215
+ [configTitle]="{
216
+ config: { content: 'Hợp đồng số: HD-2024-001' },
217
+ isShowBackToListLabel: true
218
+ }"
219
+ [configRight]="configRight"
220
+ [bodyConfig]="bodyConfig"
221
+ (outClose)="handlerClose($event)"
222
+ (outFunctionControl)="handlerFunctionControl($event)">
223
+ </libs_ui-components-pages_template-detail_v2>
224
+ `,
225
+ })
226
+ export class ContractDetailComponent {
227
+ protected bodyConfig: IPageDetailV2BodyConfig = {
228
+ getComponentOutlet: () =>
229
+ from(
230
+ import('./contract-info/contract-info.component').then(
231
+ (m) => m.ContractInfoComponent
232
+ )
233
+ ),
234
+ getDataComponentOutlet: (sectionData) =>
235
+ of({
236
+ contractId: 'HD-2024-001',
237
+ disable: sectionData?.disable ?? false,
238
+ }),
239
+ classInclude: 'p-[24px]',
240
+ };
241
+
242
+ protected configRight: IPagesTemplateDetailConfigRight[] = [
57
243
  {
58
244
  key: 'button',
59
- configButton: { label: 'Lưu thay đổi', type: 'button-primary' }
245
+ configButton: {
246
+ label: 'Duyệt hợp đồng',
247
+ type: 'button-primary',
248
+ action: () => this.handlerApprove(),
249
+ },
250
+ },
251
+ ];
252
+
253
+ protected handlerClose(event: Event): void {
254
+ event.stopPropagation();
255
+ // Navigate back
256
+ }
257
+
258
+ protected handlerFunctionControl(control: IPageDetailFunctionControl): void {
259
+ // Dùng control.setStateDisable(true) để disable toàn bộ action trong header
260
+ }
261
+
262
+ private handlerApprove(): void {
263
+ // Approve logic
264
+ }
265
+ }
266
+ ```
267
+
268
+ ### Ví dụ 4 — Điều khiển trạng thái disable từ bên ngoài qua FunctionControl
269
+
270
+ ```typescript
271
+ // invoice-detail.component.ts
272
+ import { ChangeDetectionStrategy, Component } from '@angular/core';
273
+ import { LibsUiComponentsPagesTemplateDetailV2Component } from '@libs-ui/components-pages-template-detail';
274
+ import { IPageDetailFunctionControl, IPagesTemplateDetailConfigRight } from '@libs-ui/components-pages-template-detail';
275
+
276
+ @Component({
277
+ selector: 'app-invoice-detail',
278
+ standalone: true,
279
+ changeDetection: ChangeDetectionStrategy.OnPush,
280
+ imports: [LibsUiComponentsPagesTemplateDetailV2Component],
281
+ template: `
282
+ <libs_ui-components-pages_template-detail_v2
283
+ [configTitle]="{ config: { content: 'Hóa đơn #INV-001' } }"
284
+ [configRight]="configRight"
285
+ (outClose)="handlerClose($event)"
286
+ (outFunctionControl)="handlerFunctionControl($event)"
287
+ (outStateDisable)="handlerStateDisable($event)">
288
+ </libs_ui-components-pages_template-detail_v2>
289
+ `,
290
+ })
291
+ export class InvoiceDetailComponent {
292
+ protected configRight: IPagesTemplateDetailConfigRight[] = [
293
+ {
294
+ key: 'button',
295
+ configButton: {
296
+ label: 'Lưu',
297
+ type: 'button-primary',
298
+ action: () => this.handlerSave(),
299
+ },
300
+ },
301
+ ];
302
+
303
+ private functionControl?: IPageDetailFunctionControl;
304
+
305
+ protected handlerClose(event: Event): void {
306
+ event.stopPropagation();
307
+ }
308
+
309
+ protected handlerFunctionControl(control: IPageDetailFunctionControl): void {
310
+ this.functionControl = control;
311
+ }
312
+
313
+ protected handlerStateDisable(isDisabled: boolean): void {
314
+ // React when disable state changes
315
+ }
316
+
317
+ private async handlerSave(): Promise<void> {
318
+ // Disable all header actions while saving
319
+ await this.functionControl?.setStateDisable(true);
320
+ try {
321
+ // ... save API call
322
+ } finally {
323
+ await this.functionControl?.setStateDisable(false);
60
324
  }
61
- ]"
62
- (outClose)="onBack()">
63
- <div class="p-6">
64
- <!-- Nội dung chi tiết ở đây -->
65
- <app-user-form></app-user-form>
66
- </div>
67
- </libs_ui-components-pages_template-detail>
325
+ }
326
+ }
68
327
  ```
69
328
 
70
- ## API
329
+ ## @Input() — LibsUiComponentsPagesTemplateDetailV2Component
330
+
331
+ | Input | Type | Default | Mô tả | Ví dụ |
332
+ |---|---|---|---|---|
333
+ | `[bodyConfig]` | `IPageDetailV2BodyConfig` | `{}` | Cấu hình lazy-load component vào vùng body. Khi không truyền `getComponentOutlet`, vùng body sẽ không render (dùng `ng-content` thay thế với V1). | `[bodyConfig]="{ getComponentOutlet: () => from(import('./body.component').then(m => m.BodyComponent)) }"` |
334
+ | `[classIncludeHeader]` | `string` | `undefined` | CSS class bổ sung cho dải header. | `[classIncludeHeader]="'border-b-2 border-blue-500'"` |
335
+ | `[configCenter]` | `IPagesTemplateDetailConfigCenter` | `undefined` | Cấu hình vùng giữa header — chỉ hiển thị khi `isSplitHeaderRatio` là `true`. | `[configCenter]="{ title: 'Tên bản ghi', classIncludeTitle: 'uppercase libs-ui-font-h4s' }"` |
336
+ | `[configRight]` | `Array<IPagesTemplateDetailConfigRight>` | `undefined` | Danh sách control hiển thị ở bên phải header, theo thứ tự từ trái sang phải. | `[configRight]="[{ key: 'button', configButton: { label: 'Lưu', type: 'button-primary' } }]"` |
337
+ | `[configTitle]` | `IPagesTemplateDetailConfigTitle` | `undefined` | Cấu hình vùng bên trái header: nút quay lại, tiêu đề popover, mô tả phụ, tiêu đề phụ trên cùng. | `[configTitle]="{ config: { content: 'Nguyễn Văn An' }, isShowBackToListLabel: true }"` |
338
+ | `[disable]` | `boolean` (model — two-way) | `false` | Trạng thái disable toàn bộ action trong header. Có thể bind two-way `[(disable)]`. | `[(disable)]="isDisabled"` |
339
+ | `[isSplitHeaderRatio]` | `boolean` | `undefined` | Khi `true`, header chia thành 3 vùng với tỉ lệ 24% — 52% — 24%; vùng giữa hiển thị `configCenter`. | `[isSplitHeaderRatio]="true"` |
340
+ | `[zIndex]` | `number` | `1000` | Giá trị `z-index` CSS của toàn bộ component. Tự động fallback về `1000` khi truyền `undefined`. | `[zIndex]="1200"` |
71
341
 
72
- ### libs_ui-components-pages_template-detail
342
+ ## @Input() — LibsUiComponentsPagesTemplateDetailComponent (V1, deprecated)
73
343
 
74
- #### Inputs
344
+ Tương tự V2, ngoại trừ không có `bodyConfig`. V1 có thêm `[classIncludeBody]` để thêm class cho vùng body khi dùng `ng-content`.
75
345
 
76
- | Property | Type | Default | Description |
77
- | ---------------------- | ---------------------------------------- | ----------- | -------------------------------------------------- |
78
- | `[classIncludeBody]` | `string` | `undefined` | Custom class cho phần thân trang. |
79
- | `[classIncludeHeader]` | `string` | `undefined` | Custom class cho phần header. |
80
- | `[configCenter]` | `IPagesTemplateDetailConfigCenter` | `undefined` | Cấu hình phần nội dung giữa header. |
81
- | `[configRight]` | `Array<IPagesTemplateDetailConfigRight>` | `undefined` | Danh sách các action group ở bên phải header. |
82
- | `[configTitle]` | `IPagesTemplateDetailConfigTitle` | `undefined` | Cấu hình tiêu đề, tả nút quay lại. |
83
- | `[disable]` | `boolean` (model) | `false` | Trạng thái hiệu hóa toàn bộ action trên header. |
84
- | `[isSplitHeaderRatio]` | `boolean` | `false` | Bật tỉ lệ chia header 24/52/24. |
85
- | `[zIndex]` | `number` | `1000` | Thứ tự hiển thị lớp phủ. |
346
+ | Input | Type | Default | Mô tả | Ví dụ |
347
+ |---|---|---|---|---|
348
+ | `[classIncludeBody]` | `string` | `undefined` | CSS class bổ sung cho vùng body (chỉ V1, dùng với ng-content). | `[classIncludeBody]="'p-[24px]'"` |
349
+ | `[classIncludeHeader]` | `string` | `undefined` | CSS class bổ sung cho dải header. | `[classIncludeHeader]="'shadow-sm'"` |
350
+ | `[configCenter]` | `IPagesTemplateDetailConfigCenter` | `undefined` | Cấu hình vùng giữa header. | `[configCenter]="{ title: 'Tên trang' }"` |
351
+ | `[configRight]` | `Array<IPagesTemplateDetailConfigRight>` | `undefined` | Danh sách control phía phải header. | `[configRight]="actionList"` |
352
+ | `[configTitle]` | `IPagesTemplateDetailConfigTitle` | `undefined` | Cấu hình vùng trái header. | `[configTitle]="{ config: { content: 'Tiêu đề' } }"` |
353
+ | `[disable]` | `boolean` (model) | `false` | Trạng thái disable toàn bộ action. | `[(disable)]="isDisabled"` |
354
+ | `[isSplitHeaderRatio]` | `boolean` | `undefined` | Chia header theo tỉ lệ 24/52/24. | `[isSplitHeaderRatio]="true"` |
355
+ | `[zIndex]` | `number` | `1000` | Giá trị z-index của component. | `[zIndex]="1100"` |
86
356
 
87
- #### Outputs
357
+ ## @Output()
88
358
 
89
- | Property | Type | Description |
90
- | ----------------------------------- | -------------------------------------------- | ---------------------------------------------------- |
91
- | `(outClose)` | `EventEmitter<boolean>` | Phát ra khi người dùng click nút quay lại hoặc đóng. |
92
- | `(outFunctionControl)` | `EventEmitter<IPageDetailFunctionControl>` | Cung cấp hàm điều khiển trạng thái component. |
93
- | `(outScroll)` | `EventEmitter<Event>` | Phát ra khi thực hiện cuộn trong trang. |
94
- | `(outSelectedButtonDropdown)` | `EventEmitter<IEmitSelectKey>` | Phát ra khi chọn item từ Button Dropdown. |
95
- | `(outSelectedMenuDropdown)` | `EventEmitter<IEmitSelectKey \| undefined>` | Phát ra khi chọn item từ Menu Dropdown. |
96
- | `(outSelectedRadio)` | `EventEmitter<IRadioEvent>` | Phát ra khi thay đổi giá trị Radio Group. |
97
- | `(outStateDisable)` | `EventEmitter<boolean>` | Phát ra khi trạng thái disable thay đổi. |
98
- | `(outTooltipButtonFunctionControl)` | `EventEmitter<IPopoverFunctionControlEvent>` | Cung cấp hàm điều khiển cho nút tooltip/popover. |
359
+ | Output | Type | Mô tả | Handler TS | Binding HTML |
360
+ |---|---|---|---|---|
361
+ | `(outClose)` | `boolean` | Phát ra `true` khi người dùng click nút quay lại (chevron icon hoặc nhãn "Quay lại danh sách"). | `handlerClose(event: Event): void { event.stopPropagation(); /* navigate back */ }` | `(outClose)="handlerClose($event)"` |
362
+ | `(outFunctionControl)` | `IPageDetailFunctionControl` | Phát ra object chứa các hàm điều khiển component từ bên ngoài (emit một lần trong `ngOnInit`). | `handlerFunctionControl(ctrl: IPageDetailFunctionControl): void { this.control = ctrl; }` | `(outFunctionControl)="handlerFunctionControl($event)"` |
363
+ | `(outScroll)` | `Event` | Phát ra native scroll event khi người dùng cuộn vùng body. | `handlerScroll(event: Event): void { event.stopPropagation(); /* handle scroll */ }` | `(outScroll)="handlerScroll($event)"` |
364
+ | `(outSelectedButtonDropdown)` | `IEmitSelectKey` | Phát ra khi người dùng chọn một item từ `button-dropdown` trong `configRight`. | `handlerSelectedButtonDropdown(event: IEmitSelectKey): void { event.stopPropagation(); /* handle select */ }` | `(outSelectedButtonDropdown)="handlerSelectedButtonDropdown($event)"` |
365
+ | `(outSelectedMenuDropdown)` | `IEmitSelectKey \| undefined` | Phát ra khi người dùng chọn một item từ `menu-dropdown` trong `configRight`. | `handlerSelectedMenuDropdown(event: IEmitSelectKey \| undefined): void { event.stopPropagation(); /* handle select */ }` | `(outSelectedMenuDropdown)="handlerSelectedMenuDropdown($event)"` |
366
+ | `(outSelectedRadio)` | `IRadioEvent` | Phát ra khi người dùng thay đổi lựa chọn trong `radio-group` trên header. | `handlerSelectedRadio(event: IRadioEvent): void { event.stopPropagation(); /* handle change */ }` | `(outSelectedRadio)="handlerSelectedRadio($event)"` |
367
+ | `(outStateDisable)` | `boolean` | Phát ra giá trị disable mới mỗi khi `setStateDisable()` được gọi qua FunctionControl. | `handlerStateDisable(isDisabled: boolean): void { /* react to disable change */ }` | `(outStateDisable)="handlerStateDisable($event)"` |
368
+ | `(outTooltipButtonFunctionControl)` | `IPopoverFunctionControlEvent` | Phát ra function control của popover/tooltip gắn với `tooltip-button` trong `configRight`. | `handlerTooltipControl(event: IPopoverFunctionControlEvent): void { this.tooltipControl = event; }` | `(outTooltipButtonFunctionControl)="handlerTooltipControl($event)"` |
99
369
 
100
370
  ## Types & Interfaces
101
371
 
102
372
  ```typescript
103
- export interface IPagesTemplateDetailConfigTitle extends IPopover {
373
+ import {
374
+ IPagesTemplateDetailConfigTitle,
375
+ IPagesTemplateDetailConfigRight,
376
+ IPagesTemplateDetailConfigCenter,
377
+ IPageDetailFunctionControl,
378
+ IPageDetailV2BodyConfig,
379
+ IPageDetailV2SectionData,
380
+ } from '@libs-ui/components-pages-template-detail';
381
+ ```
382
+
383
+ ### IPagesTemplateDetailConfigTitle
384
+
385
+ ```typescript
386
+ import { IPopover, IPopoverOverlay } from '@libs-ui/components-popover';
387
+
388
+ interface IPagesTemplateDetailConfigTitle extends IPopover {
389
+ /** Tiêu đề phụ hiển thị dạng dải riêng phía trên header chính (chỉ V2) */
390
+ header?: {
391
+ content?: string;
392
+ classInclude?: string;
393
+ };
394
+ /** Ẩn nút mũi tên quay lại (chevron icon). Mặc định: false */
104
395
  ignoreButtonBack?: boolean;
396
+ /**
397
+ * Tắt escape HTML tự động cho nội dung tiêu đề.
398
+ * Chỉ dùng khi nội dung đã được sanitize từ nguồn tin cậy.
399
+ * Mặc định: false (luôn escape)
400
+ */
401
+ ignoreEscapeHtml?: boolean;
402
+ /** Hiển thị mũi tên (arrow begin) trước nút quay lại */
403
+ isShowArrowBegin?: boolean;
404
+ /** Hiển thị nhãn "Quay lại danh sách" dạng link button thay vì icon */
105
405
  isShowBackToListLabel?: boolean;
406
+ /** Cấu hình mô tả phụ hiển thị bên cạnh tiêu đề chính */
106
407
  configDescription?: {
107
408
  innerView?: string;
108
409
  config: IPopoverOverlay;
109
410
  };
110
411
  }
412
+ ```
413
+
414
+ ### IPagesTemplateDetailConfigRight
415
+
416
+ ```typescript
417
+ import { IButton } from '@libs-ui/components-buttons-button';
418
+ import { IButtonDropdown } from '@libs-ui/components-buttons-dropdown';
419
+ import { IDropdown } from '@libs-ui/components-dropdown';
420
+ import { IPopover } from '@libs-ui/components-popover';
421
+ import { IRadioGroupItem } from '@libs-ui/components-radio-group';
422
+ import { ISwitch } from '@libs-ui/components-switch';
423
+
424
+ type ButtonKey =
425
+ | 'button'
426
+ | 'swicth'
427
+ | 'radio-group'
428
+ | 'circle-and-number'
429
+ | 'button-dropdown'
430
+ | 'menu-dropdown'
431
+ | 'tooltip-button'
432
+ | 'tooltip';
111
433
 
112
- export interface IPagesTemplateDetailConfigRight {
113
- key: 'button' | 'swicth' | 'radio-group' | 'button-dropdown' | 'menu-dropdown' | 'tooltip-button';
434
+ interface IPagesTemplateDetailConfigRight {
435
+ /** Loại control cần hiển thị */
436
+ key: ButtonKey;
437
+ /** CSS class bổ sung cho wrapper của control này */
438
+ classInclude?: string;
439
+ /** Trạng thái disable riêng cho control này (ưu tiên hơn disable toàn component) */
440
+ disable?: boolean;
441
+ /** Hiển thị loading spinner trên control */
442
+ isPending?: boolean;
443
+ /** Ẩn control này (dùng để điều kiện hiện/ẩn mà không cần unmount) */
444
+ ignoreShowButton?: boolean;
445
+ /** Cấu hình cho key: 'button' */
114
446
  configButton?: IButton;
447
+ /** Cấu hình cho key: 'button-dropdown' */
448
+ configButtonDropdown?: IButtonDropdown;
449
+ /** Cấu hình cho key: 'radio-group' */
450
+ configRadioGroup?: Array<IRadioGroupItem>;
451
+ /** Cấu hình cho key: 'swicth' */
115
452
  configSwicth?: ISwitch;
453
+ /** Cấu hình cho key: 'menu-dropdown' */
116
454
  configDropdown?: IDropdown;
117
- // ...
455
+ /** Cấu hình cho key: 'tooltip-button' */
456
+ configTooltipButton?: {
457
+ configTooltip?: IPopover;
458
+ configButton?: IButton;
459
+ };
460
+ }
461
+ ```
462
+
463
+ ### IPagesTemplateDetailConfigCenter
464
+
465
+ ```typescript
466
+ import { TemplateRef } from '@angular/core';
467
+ import { TYPE_TEMPLATE_REF } from '@libs-ui/interfaces-types';
468
+
469
+ interface IPagesTemplateDetailConfigCenter {
470
+ /** Text tiêu đề (tự động translate và escape HTML) */
471
+ title?: string;
472
+ /** CSS class bổ sung cho phần tử tiêu đề */
473
+ classIncludeTitle?: string;
474
+ /** TemplateRef tùy chỉnh thay thế hoàn toàn vùng giữa khi cần UI phức tạp hơn */
475
+ template?: TemplateRef<TYPE_TEMPLATE_REF>;
118
476
  }
119
477
  ```
120
478
 
121
- ## Công nghệ
479
+ ### IPageDetailFunctionControl
480
+
481
+ ```typescript
482
+ interface IPageDetailFunctionControl {
483
+ /**
484
+ * Thay đổi trạng thái disable của toàn bộ action trong header.
485
+ * Gọi setStateDisable(true) trước khi submit, setStateDisable(false) sau khi hoàn thành.
486
+ */
487
+ setStateDisable: (stateDisable: boolean) => Promise<void>;
488
+ }
489
+ ```
122
490
 
123
- | Technology | Purpose |
124
- | --------------- | ---------------------- |
125
- | Angular 18 | Framework chính |
126
- | Angular Signals | Quản lý state phản ứng |
127
- | UI Kit | Hệ thống design gốc |
128
- | SCSS | Styling chuyên biệt |
491
+ ### IPageDetailV2BodyConfig (chỉ V2)
129
492
 
130
- ## License
493
+ ```typescript
494
+ import { WritableSignal } from '@angular/core';
495
+ import { ISkeletonConfig } from '@libs-ui/components-skeleton';
496
+ import { TYPE_FUNCTION } from '@libs-ui/interfaces-types';
497
+
498
+ interface IPageDetailV2BodyConfig {
499
+ /**
500
+ * Hàm trả về Observable<Type> để lazy-load component vào vùng body.
501
+ * Nhận tham số `sectionData: IPageDetailV2SectionData` (có `disable`).
502
+ * Khi chưa resolve, hiển thị skeleton.
503
+ */
504
+ getComponentOutlet?: TYPE_FUNCTION<any>;
505
+ /**
506
+ * Hàm trả về Observable<Record> chứa data truyền vào component được load.
507
+ * Nhận tham số `sectionData: IPageDetailV2SectionData`.
508
+ */
509
+ getDataComponentOutlet?: TYPE_FUNCTION<Record<string, unknown>>;
510
+ /** Cấu hình skeleton hiển thị trong lúc đang lazy-load component */
511
+ skeletonConfig?: WritableSignal<ISkeletonConfig>;
512
+ /** CSS class bổ sung cho wrapper của vùng body */
513
+ classInclude?: string;
514
+ }
515
+
516
+ interface IPageDetailV2SectionData {
517
+ /** Trạng thái disable hiện tại của component — dùng để truyền xuống body component */
518
+ disable: boolean;
519
+ }
520
+ ```
521
+
522
+ ## Lưu ý quan trọng
523
+
524
+ ⚠️ **V1 đã deprecated**: `LibsUiComponentsPagesTemplateDetailComponent` (selector `libs_ui-components-pages_template-detail`) không còn được duy trì. Mọi trang mới BẮT BUỘC dùng `LibsUiComponentsPagesTemplateDetailV2Component`.
525
+
526
+ ⚠️ **Lỗi chính tả `swicth`**: Interface dùng `configSwicth` (không phải `configSwitch`) và key `'swicth'` — đây là tên gốc trong source, cần giữ đúng chính xác khi sử dụng.
527
+
528
+ ⚠️ **bodyConfig chỉ hoạt động với getComponentOutlet**: Khi `bodyConfig.getComponentOutlet` không được truyền, V2 sẽ không render vùng body tự động. Cần dùng `ng-content` (chỉ V1 hỗ trợ) hoặc truyền đủ cấu hình `getComponentOutlet`.
529
+
530
+ ⚠️ **outFunctionControl emit một lần duy nhất**: `outFunctionControl` chỉ emit trong `ngOnInit`. Phải lưu giá trị vào biến class để dùng sau: `private functionControl?: IPageDetailFunctionControl`.
531
+
532
+ ⚠️ **XSS tự động**: Tiêu đề trong `configTitle.config.content` mặc định được escape HTML. Nếu cần render HTML thực (ví dụ: i18n có HTML), truyền `ignoreEscapeHtml: true` — chỉ dùng khi nguồn dữ liệu là i18n key do team kiểm soát.
533
+
534
+ ⚠️ **isSplitHeaderRatio + configCenter**: `configCenter` chỉ hiển thị khi `isSplitHeaderRatio` là `true`. Truyền `configCenter` mà không bật `isSplitHeaderRatio` sẽ không có effect.
535
+
536
+ ⚠️ **Dynamic component với V2**: Khi dùng V2 làm dynamic component trong Modal hoặc page template khác, BẮT BUỘC khai báo Generic Type rõ ràng cho `ComponentRef` và gọi `.destroy()` trong `ngOnDestroy` của component cha để tránh memory leak.
537
+
538
+ ## Demo
539
+
540
+ ```bash
541
+ npx nx serve core-ui
542
+ ```
131
543
 
132
- MIT
544
+ Truy cập: http://localhost:4500/ và tìm mục "pages-template-detail" trong menu demo.
@@ -1,6 +1,6 @@
1
1
  import { AsyncPipe, NgComponentOutlet, NgTemplateOutlet } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
- import { input, model, output, computed, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { input, model, output, computed, Component, ChangeDetectionStrategy } from '@angular/core';
4
4
  import { LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';
5
5
  import { LibsUiComponentsButtonsDropdownComponent } from '@libs-ui/components-buttons-dropdown';
6
6
  import { LibsUiComponentsDropdownComponent } from '@libs-ui/components-dropdown';
@@ -1 +1 @@
1
- {"version":3,"file":"libs-ui-components-pages-template-detail.mjs","sources":["../../../../../../libs-ui/components/pages-template/detail/src/detail-v2/detail-v2.component.ts","../../../../../../libs-ui/components/pages-template/detail/src/detail-v2/detail-v2.component.html","../../../../../../libs-ui/components/pages-template/detail/src/detail.component.ts","../../../../../../libs-ui/components/pages-template/detail/src/detail.component.html","../../../../../../libs-ui/components/pages-template/detail/src/libs-ui-components-pages-template-detail.ts"],"sourcesContent":["import { AsyncPipe, NgComponentOutlet, NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, OnInit, Signal, computed, input, model, output } from '@angular/core';\nimport { IButton, LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';\nimport { LibsUiComponentsButtonsDropdownComponent } from '@libs-ui/components-buttons-dropdown';\nimport { IDropdownFunctionControlEvent, IEmitSelectKey, LibsUiComponentsDropdownComponent } from '@libs-ui/components-dropdown';\nimport { IPopoverFunctionControlEvent, LibsUiComponentsPopoverComponent, TYPE_POPOVER_EVENT } from '@libs-ui/components-popover';\nimport { LibsUiComponentsRadioGroupComponent } from '@libs-ui/components-radio-group';\nimport { IRadioEvent } from '@libs-ui/components-radio-single';\nimport { LibsUiComponentsScrollOverlayDirective } from '@libs-ui/components-scroll-overlay';\nimport { ISkeletonConfig, LibsUiComponentsSkeletonComponent } from '@libs-ui/components-skeleton';\nimport { ISwitch, ISwitchEvent, LibsUiComponentsSwitchComponent } from '@libs-ui/components-switch';\nimport { LibsUiPipesCallFunctionInTemplatePipe } from '@libs-ui/pipes-call-function-in-template';\nimport { LibsUiPipesEscapeHtmlPipe } from '@libs-ui/pipes-escape-html';\nimport { escapeHtml, get } from '@libs-ui/utils';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { IPagesTemplateDetailConfigCenter, IPagesTemplateDetailConfigRight, IPagesTemplateDetailConfigTitle } from '../interfaces/config.interface';\nimport { IPageDetailFunctionControl } from '../interfaces/function-control.interface';\nimport { IPageDetailV2BodyConfig, IPageDetailV2SectionData } from './interfaces/detail-v2.interface';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-pages_template-detail_v2',\n templateUrl: './detail-v2.component.html',\n styleUrls: ['./detail-v2.component.scss'],\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n AsyncPipe,\n NgComponentOutlet,\n NgTemplateOutlet,\n TranslateModule,\n LibsUiComponentsButtonsButtonComponent,\n LibsUiComponentsPopoverComponent,\n LibsUiComponentsRadioGroupComponent,\n LibsUiComponentsSwitchComponent,\n LibsUiComponentsDropdownComponent,\n LibsUiComponentsScrollOverlayDirective,\n LibsUiComponentsButtonsDropdownComponent,\n LibsUiComponentsSkeletonComponent,\n LibsUiPipesCallFunctionInTemplatePipe,\n LibsUiPipesEscapeHtmlPipe,\n ],\n})\nexport class LibsUiComponentsPagesTemplateDetailV2Component implements OnInit {\n // #region --- INPUTS (kế thừa từ V1) ---\n readonly zIndex = input<number, number | undefined>(1000, { transform: (val) => val ?? 1000 });\n readonly configRight = input<Array<IPagesTemplateDetailConfigRight>>();\n readonly configTitle = input<IPagesTemplateDetailConfigTitle>();\n readonly configCenter = input<IPagesTemplateDetailConfigCenter>();\n readonly classIncludeHeader = input<string>();\n readonly isSplitHeaderRatio = input<boolean>();\n // #endregion\n\n // #region --- INPUTS (mới trong V2) ---\n /** Config để lazy load component vào vùng body */\n readonly bodyConfig = input<IPageDetailV2BodyConfig, IPageDetailV2BodyConfig | undefined>({}, { transform: (v) => v || {} });\n // #endregion\n\n // #region --- MODELS ---\n readonly disable = model<boolean>(false);\n // #endregion\n\n // #region --- OUTPUTS ---\n readonly outScroll = output<Event>();\n readonly outClose = output<boolean>();\n readonly outSelectedMenuDropdown = output<IEmitSelectKey | undefined>();\n readonly outSelectedButtonDropdown = output<IEmitSelectKey>();\n readonly outFunctionControl = output<IPageDetailFunctionControl>();\n readonly outSelectedRadio = output<IRadioEvent>();\n readonly outStateDisable = output<boolean>();\n readonly outTooltipButtonFunctionControl = output<IPopoverFunctionControlEvent>();\n // #endregion\n\n // #region --- INTERNAL STATE ---\n private dropdownFunctionControl!: IDropdownFunctionControlEvent;\n protected readonly pipeEmptyConfig = { valueIsEmpty: null } as const;\n // #endregion\n\n // #region --- COMPUTED ---\n protected readonly configTitleComputed = computed(() => {\n const config = this.configTitle()?.config;\n if (!config) {\n return { content: 'i18n_back_to_list' };\n }\n if (!config.content) {\n config.content = 'i18n_back_to_list';\n return config;\n }\n return { ...config, content: escapeHtml(config.content) };\n });\n\n /** Dữ liệu state truyền vào Component Outlet body */\n protected readonly sectionData = computed<IPageDetailV2SectionData>(() => ({\n disable: this.disable(),\n }));\n\n /** Skeleton config cho Body (Dùng computed để resolve default logic) */\n protected readonly resolvedSkeletonBody: Signal<ISkeletonConfig> = computed(() => {\n return (\n get(this.bodyConfig, 'skeletonConfig') ?? {\n repeat: 3,\n styleMarginBottom: 16,\n rows: [{ item: { classInclude: 'w-full h-[100px] rounded-[8px]' } }],\n }\n );\n });\n // #endregion\n\n ngOnInit() {\n this.outFunctionControl.emit(this.FunctionsControl);\n }\n\n // #region --- PUBLIC METHODS ---\n public get FunctionsControl(): IPageDetailFunctionControl {\n return {\n setStateDisable: this.setStateDisable.bind(this),\n };\n }\n // #endregion\n\n // #region --- EVENT HANDLERS ---\n protected handlerClickAction(event: IButton) {\n if (event?.action) {\n event.action();\n }\n }\n\n protected async handlerSwitch(event: ISwitch, swicthEvent: ISwitchEvent) {\n if (event?.action) {\n await event.action(swicthEvent);\n }\n }\n\n protected handlerClose(e: Event) {\n e.stopPropagation();\n this.outClose.emit(true);\n }\n\n protected handlerPopoverEvent(event: TYPE_POPOVER_EVENT) {\n if (event !== 'click') {\n return;\n }\n this.outClose.emit(true);\n }\n\n protected handlerSelectedKey(event?: IEmitSelectKey) {\n this.outSelectedMenuDropdown.emit(event);\n this.dropdownFunctionControl?.reset();\n this.dropdownFunctionControl?.removeList();\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected handlerSelectedButtonDropdownItem(event: any) {\n this.outSelectedButtonDropdown.emit(event);\n }\n\n protected handlerDropdownFunctionControl(event: IDropdownFunctionControlEvent) {\n this.dropdownFunctionControl = event;\n }\n\n protected handlerChangeRadio(event: IRadioEvent) {\n this.outSelectedRadio.emit(event);\n }\n\n protected handlerFunctionControlTooltipButton(event: IPopoverFunctionControlEvent) {\n this.outTooltipButtonFunctionControl.emit(event);\n }\n\n protected handlerScroll(event: Event) {\n this.outScroll.emit(event);\n }\n // #endregion\n\n // #region --- PRIVATE LOGIC ---\n private async setStateDisable(stateDisable: boolean) {\n this.disable.set(stateDisable);\n this.outStateDisable.emit(this.disable());\n }\n // #endregion\n}\n","<div\n class=\"libs-ui-components-page_detail\"\n [style.zIndex]=\"zIndex()\">\n <!-- ===================== HEADER ===================== -->\n <!-- Giữ nguyên hoàn toàn từ V1 -->\n @if (configTitle()?.header?.content; as headerContent) {\n <div class=\"libs-ui-font-h3s py-[10px] pl-[24px] libs-ui-border-bottom-general bg-white {{ configTitle()?.header?.classInclude || '' }}\">{{ headerContent | translate }}</div>\n }\n <div\n [class.row]=\"!isSplitHeaderRatio()\"\n class=\"flex items-center px-[16px] py-[8px] justify-between bg-white libs-ui-border-top-general {{ classIncludeHeader() || '' }}\">\n <div\n [class.columns-8]=\"!isSplitHeaderRatio()\"\n [class.w-[24%]]=\"isSplitHeaderRatio()\">\n <div class=\"flex items-center\">\n @if (!configTitle()?.ignoreButtonBack) {\n <i\n class=\"libs-ui-icon-chevron-right rotate-[180deg] before:text-[16px] mr-[8px] cursor-pointer text-[var(--libs-ui-color-default)]\"\n (click)=\"handlerClose($event)\"\n (keydown.enter)=\"handlerClose($event)\"></i>\n }\n <div class=\"flex w-full items-center\">\n @if (configTitle()?.isShowBackToListLabel) {\n <libs_ui-components-buttons-button\n [label]=\"'i18n_back_to_list'\"\n [classLabel]=\"'lib-ui-font-h6m'\"\n [type]=\"'button-link-primary'\"\n [classInclude]=\"'!p-0'\"\n (outClick)=\"handlerClose($event)\" />\n }\n @if (configTitle()?.config; as config) {\n <libs_ui-components-popover\n [config]=\"configTitleComputed()\"\n [type]=\"'text'\"\n [mode]=\"'hover'\"\n [classInclude]=\"'cursor-pointer ' + (config.classInclude || 'text-[var(--libs-ui-color-default)] libs-ui-font-h6m')\"\n [innerHtml]=\"config.content ? (!configTitle()?.ignoreEscapeHtml ? (config.content | LibsUiPipesEscapeHtmlPipe | translate) : (config.content | translate)) : '&mdash;'\"\n (outEvent)=\"handlerPopoverEvent($event)\" />\n }\n @if (configTitle()?.configDescription; as configDescription) {\n <libs_ui-components-popover\n [config]=\"configDescription.config\"\n [type]=\"'text'\"\n [mode]=\"'hover'\"\n [classInclude]=\"configDescription.config.classInclude || 'libs-ui-font-h6r text-[#6a7383]'\"\n [innerHtml]=\"configDescription.innerView | LibsUiPipesEscapeHtmlPipe | translate\" />\n }\n </div>\n </div>\n </div>\n @if (isSplitHeaderRatio() && configCenter(); as configCenter) {\n <div class=\"w-[52%] flex items-center justify-center px-[48px]\">\n @if (!configCenter.template) {\n <libs_ui-components-popover\n type=\"text\"\n [config]=\"{\n maxWidth: 250,\n zIndex: zIndex() + 1,\n }\"\n [classInclude]=\"configCenter.classIncludeTitle ?? 'uppercase libs-ui-font-h4s'\"\n [innerHtml]=\"configCenter.title ? (configCenter.title | translate | LibsUiPipesEscapeHtmlPipe) : '&mdash'\" />\n } @else {\n <ng-container *ngTemplateOutlet=\"configCenter.template\" />\n }\n </div>\n }\n <div\n class=\"flex justify-end items-center\"\n [class.columns-4]=\"!isSplitHeaderRatio()\"\n [class.w-[24%]]=\"isSplitHeaderRatio()\">\n @for (item of configRight(); track $index; let last = $last) {\n <div [class.mr-[12px]]=\"!last\">\n @if (item.key === 'button' && item.configButton; as configButton) {\n <libs_ui-components-buttons-button\n [label]=\"configButton.label || ''\"\n [classLabel]=\"configButton.classLabel || ''\"\n [type]=\"configButton.type || 'button-primary'\"\n [classInclude]=\"configButton.classInclude || ''\"\n [classIconLeft]=\"configButton.classIconLeft || ''\"\n [iconOnlyType]=\"configButton.iconOnlyType || false\"\n [classIconRight]=\"configButton.classIconRight || ''\"\n [popover]=\"configButton.popover || {}\"\n [disable]=\"configButton.disable || disable()\"\n [isPending]=\"configButton.isPending || false\"\n (outClick)=\"handlerClickAction(configButton)\" />\n }\n @if (item.key === 'swicth' && !item.ignoreShowButton && item.configSwicth; as configSwicth) {\n <libs_ui-components-switch\n [active]=\"configSwicth.active || false\"\n [disable]=\"configSwicth.disable || disable()\"\n (outSwitch)=\"handlerSwitch(configSwicth, $event)\" />\n }\n @if (item.key === 'menu-dropdown' && item.configDropdown; as configDropdown) {\n <libs_ui-components-dropdown\n [isNgContent]=\"true\"\n [zIndex]=\"2004\"\n [listConfig]=\"configDropdown.listConfig\"\n [listHiddenInputSearch]=\"true\"\n [popoverCustomConfig]=\"configDropdown.popoverCustomConfig\"\n (outSelectKey)=\"handlerSelectedKey($event)\"\n (outFunctionsControl)=\"handlerDropdownFunctionControl($event)\">\n <libs_ui-components-buttons-button\n [iconOnlyType]=\"true\"\n [classIconLeft]=\"'libs-ui-icon-more-vertical text-[#333333] text-[12px] {{ configDropdown.classInclude }}'\"\n [classInclude]=\"'p-[7px] libs-ui-border-general'\"\n [type]=\"'button-third'\"\n [ignoreStopPropagationEvent]=\"true\" />\n </libs_ui-components-dropdown>\n }\n @if (item.key === 'button-dropdown' && item.configButtonDropdown; as configDropdown) {\n <libs_ui-components-buttons-dropdown\n [applyNow]=\"true\"\n [label]=\"item.configButtonDropdown.label || ' '\"\n [classIconRight]=\"item.configButtonDropdown.classIconRight || ' '\"\n [classIconLeft]=\"item.configButtonDropdown.classIconLeft || ' '\"\n [typeButton]=\"item.configButtonDropdown.type || 'button-secondary'\"\n [items]=\"item.configButtonDropdown.items || []\"\n [fieldDisplay]=\"item.configButtonDropdown.fieldDisplay\"\n [popupConfig]=\"item.configButtonDropdown.popupConfig || { width: 205, maxWidth: 408, maxHeight: 48, zIndex: 100, direction: 'bottom' }\"\n (outSelectItem)=\"handlerSelectedButtonDropdownItem($event)\" />\n }\n @if (item.key === 'radio-group' && item.configRadioGroup; as configRadioGroup) {\n <libs_ui-components-radio-group\n [groups]=\"configRadioGroup\"\n [horizontal]=\"true\"\n [typeRadio]=\"'medium'\"\n [ignoreClassMarginLastItem]=\"true\"\n (outChange)=\"handlerChangeRadio($event)\" />\n }\n @if (item.key === 'tooltip-button' && item.configTooltipButton; as configTooltipButton) {\n <libs_ui-components-popover\n [type]=\"configTooltipButton.configTooltip?.type || 'other'\"\n [config]=\"configTooltipButton.configTooltip?.config\">\n <libs_ui-components-buttons-button\n [type]=\"configTooltipButton.configButton?.type || 'button-third'\"\n [classIconLeft]=\"configTooltipButton.configButton?.classIconLeft || 'libs-ui-icon-more-vertical rotate-[90deg] mr-0'\"\n [label]=\"configTooltipButton.configButton?.label || ''\"\n [iconOnlyType]=\"configTooltipButton.configButton?.iconOnlyType ?? false\"\n [popover]=\"configTooltipButton.configButton?.popover || {}\"\n (outFunctionsControl)=\"handlerFunctionControlTooltipButton($event)\"\n [ignoreStopPropagationEvent]=\"true\"\n [disable]=\"configTooltipButton.configButton?.disable ?? false\" />\n </libs_ui-components-popover>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- ===================== BODY ===================== -->\n @if (bodyConfig().getComponentOutlet; as getBodyComponentOutlet) {\n <!-- Lazy load mode: Hiển thị skeleton khi đang load, sau đó render component -->\n <div\n class=\"libs-ui-components-page_detail-body {{ bodyConfig().classInclude || '' }}\"\n LibsUiComponentsScrollOverlayDirective\n (outScroll)=\"handlerScroll($event)\">\n @let constHtmlCompBody = undefined | LibsUiPipesCallFunctionInTemplatePipe: getBodyComponentOutlet : sectionData() : null : pipeEmptyConfig | async;\n @let constHtmlInputsBody = undefined | LibsUiPipesCallFunctionInTemplatePipe: bodyConfig().getDataComponentOutlet : sectionData() : null : pipeEmptyConfig | async;\n @if (constHtmlCompBody) {\n <ng-container *ngComponentOutlet=\"constHtmlCompBody; inputs: constHtmlInputsBody\" />\n } @else {\n <libs_ui-components-skeleton [config]=\"resolvedSkeletonBody()\" />\n }\n </div>\n }\n</div>\n","import { NgTemplateOutlet } from '@angular/common';\nimport { Component, computed, input, model, OnInit, output } from '@angular/core';\nimport { IButton, LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';\nimport { LibsUiComponentsButtonsDropdownComponent } from '@libs-ui/components-buttons-dropdown';\nimport { IDropdownFunctionControlEvent, IEmitSelectKey, LibsUiComponentsDropdownComponent } from '@libs-ui/components-dropdown';\nimport { IPopoverFunctionControlEvent, LibsUiComponentsPopoverComponent, TYPE_POPOVER_EVENT } from '@libs-ui/components-popover';\nimport { LibsUiComponentsRadioGroupComponent } from '@libs-ui/components-radio-group';\nimport { IRadioEvent } from '@libs-ui/components-radio-single';\nimport { LibsUiComponentsScrollOverlayDirective } from '@libs-ui/components-scroll-overlay';\nimport { ISwitch, ISwitchEvent, LibsUiComponentsSwitchComponent } from '@libs-ui/components-switch';\nimport { LibsUiPipesEscapeHtmlPipe } from '@libs-ui/pipes-escape-html';\nimport { escapeHtml } from '@libs-ui/utils';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { IPagesTemplateDetailConfigCenter, IPagesTemplateDetailConfigRight, IPagesTemplateDetailConfigTitle } from './interfaces/config.interface';\nimport { IPageDetailFunctionControl } from './interfaces/function-control.interface';\n/**\n * @deprecated Use {@link LibsUiComponentsPagesTemplateDetailV2Component} instead.\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-pages_template-detail',\n templateUrl: './detail.component.html',\n styleUrls: ['./detail.component.scss'],\n standalone: true,\n imports: [\n TranslateModule,\n NgTemplateOutlet,\n LibsUiComponentsButtonsButtonComponent,\n LibsUiComponentsPopoverComponent,\n LibsUiComponentsRadioGroupComponent,\n LibsUiComponentsSwitchComponent,\n LibsUiComponentsDropdownComponent,\n LibsUiComponentsScrollOverlayDirective,\n LibsUiComponentsButtonsDropdownComponent,\n LibsUiPipesEscapeHtmlPipe,\n ],\n})\nexport class LibsUiComponentsPagesTemplateDetailComponent implements OnInit {\n private dropdownFunctionControl!: IDropdownFunctionControlEvent;\n protected configTitleComputed = computed(() => {\n const config = this.configTitle()?.config;\n if (!config) {\n return { content: 'i18n_back_to_list' };\n }\n\n if (!config.content) {\n config.content = 'i18n_back_to_list';\n return config;\n }\n\n return { ...config, content: escapeHtml(config.content) };\n });\n\n readonly zIndex = input<number, number | undefined>(1000, { transform: (val) => val ?? 1000 });\n readonly configRight = input<Array<IPagesTemplateDetailConfigRight>>();\n readonly configTitle = input<IPagesTemplateDetailConfigTitle>();\n readonly configCenter = input<IPagesTemplateDetailConfigCenter>();\n readonly classIncludeHeader = input<string>();\n readonly classIncludeBody = input<string>();\n readonly disable = model<boolean>(false);\n readonly isSplitHeaderRatio = input<boolean>(); // dùng khi muốn chia header làm 3 phần theo tỉ lệ 24 52 24\n\n readonly outScroll = output<Event>();\n readonly outClose = output<boolean>();\n readonly outSelectedMenuDropdown = output<IEmitSelectKey | undefined>();\n readonly outSelectedButtonDropdown = output<IEmitSelectKey>();\n readonly outFunctionControl = output<IPageDetailFunctionControl>();\n readonly outSelectedRadio = output<IRadioEvent>();\n readonly outStateDisable = output<boolean>();\n readonly outTooltipButtonFunctionControl = output<IPopoverFunctionControlEvent>();\n\n ngOnInit() {\n this.outFunctionControl.emit(this.FunctionsControl);\n }\n\n public get FunctionsControl(): IPageDetailFunctionControl {\n return {\n setStateDisable: this.setStateDisable.bind(this),\n };\n }\n\n protected handlerClickAction(event: IButton) {\n if (event?.action) {\n event.action();\n }\n }\n\n protected async handlerSwitch(event: ISwitch, swicthEvent: ISwitchEvent) {\n if (event?.action) {\n await event.action(swicthEvent);\n }\n }\n\n protected handlerClose(e: Event) {\n e.stopPropagation();\n this.outClose.emit(true);\n }\n\n protected handlerPopoverEvent(event: TYPE_POPOVER_EVENT) {\n if (event !== 'click') {\n return;\n }\n this.outClose.emit(true);\n }\n\n protected handlerSelectedKey(event?: IEmitSelectKey) {\n this.outSelectedMenuDropdown.emit(event);\n this.dropdownFunctionControl?.reset(); //lỗi chọn lần 2 (chưa reset thì keySelected chưa reset nên không chọn tiếp vào lựa chọn cũ)\n this.dropdownFunctionControl?.removeList();\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected handlerSelectedButtonDropdownItem(event: any) {\n this.outSelectedButtonDropdown.emit(event);\n }\n\n protected handlerDropdownFunctionControl(event: IDropdownFunctionControlEvent) {\n this.dropdownFunctionControl = event;\n }\n\n private async setStateDisable(stateDisable: boolean) {\n this.disable.set(stateDisable);\n this.outStateDisable.emit(this.disable());\n }\n\n protected handlerChangeRadio(event: IRadioEvent) {\n this.outSelectedRadio.emit(event);\n }\n\n protected handlerFunctionControlTooltipButton(event: IPopoverFunctionControlEvent) {\n this.outTooltipButtonFunctionControl.emit(event);\n }\n\n protected handlerScroll(event: Event) {\n this.outScroll.emit(event);\n }\n}\n","<div\n class=\"libs-ui-components-page_detail\"\n [style.zIndex]=\"zIndex()\">\n <div\n [class.row]=\"!isSplitHeaderRatio()\"\n class=\"flex items-center px-[16px] py-[8px] justify-between bg-white libs-ui-border-top-general {{ classIncludeHeader() || '' }}\">\n <div\n [class.columns-8]=\"!isSplitHeaderRatio()\"\n [class.w-[24%]]=\"isSplitHeaderRatio()\">\n <div class=\"flex items-center\">\n @if (!configTitle()?.ignoreButtonBack) {\n <i\n class=\"libs-ui-icon-chevron-right rotate-[180deg] before:text-[16px] mr-[8px] cursor-pointer text-[var(--libs-ui-color-default)]\"\n (click)=\"handlerClose($event)\"\n (keydown.enter)=\"handlerClose($event)\"></i>\n }\n <div class=\"flex w-full items-center\">\n @if (configTitle()?.isShowBackToListLabel) {\n <libs_ui-components-buttons-button\n [label]=\"'i18n_back_to_list'\"\n [classLabel]=\"'lib-ui-font-h6m'\"\n [type]=\"'button-link-primary'\"\n [classInclude]=\"'!p-0'\"\n (outClick)=\"handlerClose($event)\" />\n }\n @if (configTitle()?.config; as config) {\n <libs_ui-components-popover\n [config]=\"configTitleComputed()\"\n [type]=\"'text'\"\n [mode]=\"'hover'\"\n [classInclude]=\"'cursor-pointer ' + (config.classInclude || 'text-[var(--libs-ui-color-default)] libs-ui-font-h6m')\"\n [innerHtml]=\"config.content ? (!configTitle()?.ignoreEscapeHtml ? (config.content | LibsUiPipesEscapeHtmlPipe | translate) : (config.content | translate)) : '&mdash;'\"\n (outEvent)=\"handlerPopoverEvent($event)\" />\n }\n @if (configTitle()?.configDescription; as configDescription) {\n <libs_ui-components-popover\n [config]=\"configDescription.config\"\n [type]=\"'text'\"\n [mode]=\"'hover'\"\n [classInclude]=\"configDescription.config.classInclude || 'libs-ui-font-h6r text-[#6a7383]'\"\n [innerHtml]=\"configDescription.innerView | LibsUiPipesEscapeHtmlPipe | translate\" />\n }\n </div>\n </div>\n </div>\n @if (isSplitHeaderRatio() && configCenter(); as configCenter) {\n <div class=\"w-[52%] flex items-center justify-center px-[48px]\">\n @if (!configCenter.template) {\n <libs_ui-components-popover\n type=\"text\"\n [config]=\"{\n maxWidth: 250,\n zIndex: zIndex() + 1,\n }\"\n [classInclude]=\"configCenter.classIncludeTitle ?? 'uppercase libs-ui-font-h4s'\"\n [innerHtml]=\"configCenter.title ? (configCenter.title | translate | LibsUiPipesEscapeHtmlPipe) : '&mdash'\" />\n } @else {\n <ng-container *ngTemplateOutlet=\"configCenter.template\" />\n }\n </div>\n }\n <div\n class=\"flex justify-end items-center\"\n [class.columns-4]=\"!isSplitHeaderRatio()\"\n [class.w-[24%]]=\"isSplitHeaderRatio()\">\n @for (item of configRight(); track $index; let last = $last) {\n <div [class.mr-[12px]]=\"!last\">\n @if (item.key === 'button' && item.configButton; as configButton) {\n <libs_ui-components-buttons-button\n [label]=\"configButton.label || ''\"\n [classLabel]=\"configButton.classLabel || ''\"\n [type]=\"configButton.type || 'button-primary'\"\n [classInclude]=\"configButton.classInclude || ''\"\n [classIconLeft]=\"configButton.classIconLeft || ''\"\n [iconOnlyType]=\"configButton.iconOnlyType || false\"\n [classIconRight]=\"configButton.classIconRight || ''\"\n [popover]=\"configButton.popover || {}\"\n [disable]=\"configButton.disable || disable()\"\n [isPending]=\"configButton.isPending || false\"\n (outClick)=\"handlerClickAction(configButton)\" />\n }\n @if (item.key === 'swicth' && !item.ignoreShowButton && item.configSwicth; as configSwicth) {\n <libs_ui-components-switch\n [active]=\"configSwicth.active || false\"\n [disable]=\"configSwicth.disable || disable()\"\n (outSwitch)=\"handlerSwitch(configSwicth, $event)\" />\n }\n @if (item.key === 'menu-dropdown' && item.configDropdown; as configDropdown) {\n <libs_ui-components-dropdown\n [isNgContent]=\"true\"\n [zIndex]=\"2004\"\n [listConfig]=\"configDropdown.listConfig\"\n [listHiddenInputSearch]=\"true\"\n [popoverCustomConfig]=\"configDropdown.popoverCustomConfig\"\n (outSelectKey)=\"handlerSelectedKey($event)\"\n (outFunctionsControl)=\"handlerDropdownFunctionControl($event)\">\n <libs_ui-components-buttons-button\n [iconOnlyType]=\"true\"\n [classIconLeft]=\"'libs-ui-icon-more-vertical text-[#333333] text-[12px] {{ configDropdown.classInclude }}'\"\n [classInclude]=\"'p-[7px] libs-ui-border-general'\"\n [type]=\"'button-third'\"\n [ignoreStopPropagationEvent]=\"true\" />\n </libs_ui-components-dropdown>\n }\n @if (item.key === 'button-dropdown' && item.configButtonDropdown; as configDropdown) {\n <libs_ui-components-buttons-dropdown\n [applyNow]=\"true\"\n [label]=\"item.configButtonDropdown.label || ' '\"\n [classIconRight]=\"item.configButtonDropdown.classIconRight || ' '\"\n [classIconLeft]=\"item.configButtonDropdown.classIconLeft || ' '\"\n [typeButton]=\"item.configButtonDropdown.type || 'button-secondary'\"\n [items]=\"item.configButtonDropdown.items || []\"\n [fieldDisplay]=\"item.configButtonDropdown.fieldDisplay\"\n [popupConfig]=\"item.configButtonDropdown.popupConfig || { width: 205, maxWidth: 408, maxHeight: 48, zIndex: 100, direction: 'bottom' }\"\n (outSelectItem)=\"handlerSelectedButtonDropdownItem($event)\" />\n }\n\n @if (item.key === 'radio-group' && item.configRadioGroup; as configRadioGroup) {\n <libs_ui-components-radio-group\n [groups]=\"configRadioGroup\"\n [horizontal]=\"true\"\n [typeRadio]=\"'medium'\"\n [ignoreClassMarginLastItem]=\"true\"\n (outChange)=\"handlerChangeRadio($event)\" />\n }\n\n @if (item.key === 'tooltip-button' && item.configTooltipButton; as configTooltipButton) {\n <libs_ui-components-popover\n [type]=\"configTooltipButton.configTooltip?.type || 'other'\"\n [config]=\"configTooltipButton.configTooltip?.config\">\n <libs_ui-components-buttons-button\n [type]=\"configTooltipButton.configButton?.type || 'button-third'\"\n [classIconLeft]=\"configTooltipButton.configButton?.classIconLeft || 'libs-ui-icon-more-vertical rotate-[90deg] mr-0'\"\n [label]=\"configTooltipButton.configButton?.label || ''\"\n [iconOnlyType]=\"configTooltipButton.configButton?.iconOnlyType ?? false\"\n [popover]=\"configTooltipButton.configButton?.popover || {}\"\n (outFunctionsControl)=\"handlerFunctionControlTooltipButton($event)\"\n [ignoreStopPropagationEvent]=\"true\"\n [disable]=\"configTooltipButton.configButton?.disable ?? false\" />\n </libs_ui-components-popover>\n }\n </div>\n }\n </div>\n </div>\n\n <div\n class=\"libs-ui-components-page_detail-body {{ classIncludeBody() }}\"\n LibsUiComponentsScrollOverlayDirective\n (outScroll)=\"handlerScroll($event)\">\n <ng-content></ng-content>\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"libs-ui-components-pages-template-detail.mjs","sources":["../../../../../../libs-ui/components/pages-template/detail/src/detail-v2/detail-v2.component.ts","../../../../../../libs-ui/components/pages-template/detail/src/detail-v2/detail-v2.component.html","../../../../../../libs-ui/components/pages-template/detail/src/detail.component.ts","../../../../../../libs-ui/components/pages-template/detail/src/detail.component.html","../../../../../../libs-ui/components/pages-template/detail/src/libs-ui-components-pages-template-detail.ts"],"sourcesContent":["import { AsyncPipe, NgComponentOutlet, NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, OnInit, Signal, computed, input, model, output } from '@angular/core';\nimport { IButton, LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';\nimport { LibsUiComponentsButtonsDropdownComponent } from '@libs-ui/components-buttons-dropdown';\nimport { IDropdownFunctionControlEvent, IEmitSelectKey, LibsUiComponentsDropdownComponent } from '@libs-ui/components-dropdown';\nimport { IPopoverFunctionControlEvent, LibsUiComponentsPopoverComponent, TYPE_POPOVER_EVENT } from '@libs-ui/components-popover';\nimport { LibsUiComponentsRadioGroupComponent } from '@libs-ui/components-radio-group';\nimport { IRadioEvent } from '@libs-ui/components-radio-single';\nimport { LibsUiComponentsScrollOverlayDirective } from '@libs-ui/components-scroll-overlay';\nimport { ISkeletonConfig, LibsUiComponentsSkeletonComponent } from '@libs-ui/components-skeleton';\nimport { ISwitch, ISwitchEvent, LibsUiComponentsSwitchComponent } from '@libs-ui/components-switch';\nimport { LibsUiPipesCallFunctionInTemplatePipe } from '@libs-ui/pipes-call-function-in-template';\nimport { LibsUiPipesEscapeHtmlPipe } from '@libs-ui/pipes-escape-html';\nimport { escapeHtml, get } from '@libs-ui/utils';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { IPagesTemplateDetailConfigCenter, IPagesTemplateDetailConfigRight, IPagesTemplateDetailConfigTitle } from '../interfaces/config.interface';\nimport { IPageDetailFunctionControl } from '../interfaces/function-control.interface';\nimport { IPageDetailV2BodyConfig, IPageDetailV2SectionData } from './interfaces/detail-v2.interface';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-pages_template-detail_v2',\n templateUrl: './detail-v2.component.html',\n styleUrls: ['./detail-v2.component.scss'],\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n AsyncPipe,\n NgComponentOutlet,\n NgTemplateOutlet,\n TranslateModule,\n LibsUiComponentsButtonsButtonComponent,\n LibsUiComponentsPopoverComponent,\n LibsUiComponentsRadioGroupComponent,\n LibsUiComponentsSwitchComponent,\n LibsUiComponentsDropdownComponent,\n LibsUiComponentsScrollOverlayDirective,\n LibsUiComponentsButtonsDropdownComponent,\n LibsUiComponentsSkeletonComponent,\n LibsUiPipesCallFunctionInTemplatePipe,\n LibsUiPipesEscapeHtmlPipe,\n ],\n})\nexport class LibsUiComponentsPagesTemplateDetailV2Component implements OnInit {\n // #region --- INPUTS (kế thừa từ V1) ---\n readonly zIndex = input<number, number | undefined>(1000, { transform: (val) => val ?? 1000 });\n readonly configRight = input<Array<IPagesTemplateDetailConfigRight>>();\n readonly configTitle = input<IPagesTemplateDetailConfigTitle>();\n readonly configCenter = input<IPagesTemplateDetailConfigCenter>();\n readonly classIncludeHeader = input<string>();\n readonly isSplitHeaderRatio = input<boolean>();\n // #endregion\n\n // #region --- INPUTS (mới trong V2) ---\n /** Config để lazy load component vào vùng body */\n readonly bodyConfig = input<IPageDetailV2BodyConfig, IPageDetailV2BodyConfig | undefined>({}, { transform: (v) => v || {} });\n // #endregion\n\n // #region --- MODELS ---\n readonly disable = model<boolean>(false);\n // #endregion\n\n // #region --- OUTPUTS ---\n readonly outScroll = output<Event>();\n readonly outClose = output<boolean>();\n readonly outSelectedMenuDropdown = output<IEmitSelectKey | undefined>();\n readonly outSelectedButtonDropdown = output<IEmitSelectKey>();\n readonly outFunctionControl = output<IPageDetailFunctionControl>();\n readonly outSelectedRadio = output<IRadioEvent>();\n readonly outStateDisable = output<boolean>();\n readonly outTooltipButtonFunctionControl = output<IPopoverFunctionControlEvent>();\n // #endregion\n\n // #region --- INTERNAL STATE ---\n private dropdownFunctionControl!: IDropdownFunctionControlEvent;\n protected readonly pipeEmptyConfig = { valueIsEmpty: null } as const;\n // #endregion\n\n // #region --- COMPUTED ---\n protected readonly configTitleComputed = computed(() => {\n const config = this.configTitle()?.config;\n if (!config) {\n return { content: 'i18n_back_to_list' };\n }\n if (!config.content) {\n config.content = 'i18n_back_to_list';\n return config;\n }\n return { ...config, content: escapeHtml(config.content) };\n });\n\n /** Dữ liệu state truyền vào Component Outlet body */\n protected readonly sectionData = computed<IPageDetailV2SectionData>(() => ({\n disable: this.disable(),\n }));\n\n /** Skeleton config cho Body (Dùng computed để resolve default logic) */\n protected readonly resolvedSkeletonBody: Signal<ISkeletonConfig> = computed(() => {\n return (\n get(this.bodyConfig, 'skeletonConfig') ?? {\n repeat: 3,\n styleMarginBottom: 16,\n rows: [{ item: { classInclude: 'w-full h-[100px] rounded-[8px]' } }],\n }\n );\n });\n // #endregion\n\n ngOnInit() {\n this.outFunctionControl.emit(this.FunctionsControl);\n }\n\n // #region --- PUBLIC METHODS ---\n public get FunctionsControl(): IPageDetailFunctionControl {\n return {\n setStateDisable: this.setStateDisable.bind(this),\n };\n }\n // #endregion\n\n // #region --- EVENT HANDLERS ---\n protected handlerClickAction(event: IButton) {\n if (event?.action) {\n event.action();\n }\n }\n\n protected async handlerSwitch(event: ISwitch, swicthEvent: ISwitchEvent) {\n if (event?.action) {\n await event.action(swicthEvent);\n }\n }\n\n protected handlerClose(e: Event) {\n e.stopPropagation();\n this.outClose.emit(true);\n }\n\n protected handlerPopoverEvent(event: TYPE_POPOVER_EVENT) {\n if (event !== 'click') {\n return;\n }\n this.outClose.emit(true);\n }\n\n protected handlerSelectedKey(event?: IEmitSelectKey) {\n this.outSelectedMenuDropdown.emit(event);\n this.dropdownFunctionControl?.reset();\n this.dropdownFunctionControl?.removeList();\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected handlerSelectedButtonDropdownItem(event: any) {\n this.outSelectedButtonDropdown.emit(event);\n }\n\n protected handlerDropdownFunctionControl(event: IDropdownFunctionControlEvent) {\n this.dropdownFunctionControl = event;\n }\n\n protected handlerChangeRadio(event: IRadioEvent) {\n this.outSelectedRadio.emit(event);\n }\n\n protected handlerFunctionControlTooltipButton(event: IPopoverFunctionControlEvent) {\n this.outTooltipButtonFunctionControl.emit(event);\n }\n\n protected handlerScroll(event: Event) {\n this.outScroll.emit(event);\n }\n // #endregion\n\n // #region --- PRIVATE LOGIC ---\n private async setStateDisable(stateDisable: boolean) {\n this.disable.set(stateDisable);\n this.outStateDisable.emit(this.disable());\n }\n // #endregion\n}\n","<div\n class=\"libs-ui-components-page_detail\"\n [style.zIndex]=\"zIndex()\">\n <!-- ===================== HEADER ===================== -->\n <!-- Giữ nguyên hoàn toàn từ V1 -->\n @if (configTitle()?.header?.content; as headerContent) {\n <div class=\"libs-ui-font-h3s py-[10px] pl-[24px] libs-ui-border-bottom-general bg-white {{ configTitle()?.header?.classInclude || '' }}\">{{ headerContent | translate }}</div>\n }\n <div\n [class.row]=\"!isSplitHeaderRatio()\"\n class=\"flex items-center px-[16px] py-[8px] justify-between bg-white libs-ui-border-top-general {{ classIncludeHeader() || '' }}\">\n <div\n [class.columns-8]=\"!isSplitHeaderRatio()\"\n [class.w-[24%]]=\"isSplitHeaderRatio()\">\n <div class=\"flex items-center\">\n @if (!configTitle()?.ignoreButtonBack) {\n <i\n class=\"libs-ui-icon-chevron-right rotate-[180deg] before:text-[16px] mr-[8px] cursor-pointer text-[var(--libs-ui-color-default)]\"\n (click)=\"handlerClose($event)\"\n (keydown.enter)=\"handlerClose($event)\"></i>\n }\n <div class=\"flex w-full items-center\">\n @if (configTitle()?.isShowBackToListLabel) {\n <libs_ui-components-buttons-button\n [label]=\"'i18n_back_to_list'\"\n [classLabel]=\"'lib-ui-font-h6m'\"\n [type]=\"'button-link-primary'\"\n [classInclude]=\"'!p-0'\"\n (outClick)=\"handlerClose($event)\" />\n }\n @if (configTitle()?.config; as config) {\n <libs_ui-components-popover\n [config]=\"configTitleComputed()\"\n [type]=\"'text'\"\n [mode]=\"'hover'\"\n [classInclude]=\"'cursor-pointer ' + (config.classInclude || 'text-[var(--libs-ui-color-default)] libs-ui-font-h6m')\"\n [innerHtml]=\"config.content ? (!configTitle()?.ignoreEscapeHtml ? (config.content | LibsUiPipesEscapeHtmlPipe | translate) : (config.content | translate)) : '&mdash;'\"\n (outEvent)=\"handlerPopoverEvent($event)\" />\n }\n @if (configTitle()?.configDescription; as configDescription) {\n <libs_ui-components-popover\n [config]=\"configDescription.config\"\n [type]=\"'text'\"\n [mode]=\"'hover'\"\n [classInclude]=\"configDescription.config.classInclude || 'libs-ui-font-h6r text-[#6a7383]'\"\n [innerHtml]=\"configDescription.innerView | LibsUiPipesEscapeHtmlPipe | translate\" />\n }\n </div>\n </div>\n </div>\n @if (isSplitHeaderRatio() && configCenter(); as configCenter) {\n <div class=\"w-[52%] flex items-center justify-center px-[48px]\">\n @if (!configCenter.template) {\n <libs_ui-components-popover\n type=\"text\"\n [config]=\"{\n maxWidth: 250,\n zIndex: zIndex() + 1,\n }\"\n [classInclude]=\"configCenter.classIncludeTitle ?? 'uppercase libs-ui-font-h4s'\"\n [innerHtml]=\"configCenter.title ? (configCenter.title | translate | LibsUiPipesEscapeHtmlPipe) : '&mdash'\" />\n } @else {\n <ng-container *ngTemplateOutlet=\"configCenter.template\" />\n }\n </div>\n }\n <div\n class=\"flex justify-end items-center\"\n [class.columns-4]=\"!isSplitHeaderRatio()\"\n [class.w-[24%]]=\"isSplitHeaderRatio()\">\n @for (item of configRight(); track $index; let last = $last) {\n <div [class.mr-[12px]]=\"!last\">\n @if (item.key === 'button' && item.configButton; as configButton) {\n <libs_ui-components-buttons-button\n [label]=\"configButton.label || ''\"\n [classLabel]=\"configButton.classLabel || ''\"\n [type]=\"configButton.type || 'button-primary'\"\n [classInclude]=\"configButton.classInclude || ''\"\n [classIconLeft]=\"configButton.classIconLeft || ''\"\n [iconOnlyType]=\"configButton.iconOnlyType || false\"\n [classIconRight]=\"configButton.classIconRight || ''\"\n [popover]=\"configButton.popover || {}\"\n [disable]=\"configButton.disable || disable()\"\n [isPending]=\"configButton.isPending || false\"\n (outClick)=\"handlerClickAction(configButton)\" />\n }\n @if (item.key === 'swicth' && !item.ignoreShowButton && item.configSwicth; as configSwicth) {\n <libs_ui-components-switch\n [active]=\"configSwicth.active || false\"\n [disable]=\"configSwicth.disable || disable()\"\n (outSwitch)=\"handlerSwitch(configSwicth, $event)\" />\n }\n @if (item.key === 'menu-dropdown' && item.configDropdown; as configDropdown) {\n <libs_ui-components-dropdown\n [isNgContent]=\"true\"\n [zIndex]=\"2004\"\n [listConfig]=\"configDropdown.listConfig\"\n [listHiddenInputSearch]=\"true\"\n [popoverCustomConfig]=\"configDropdown.popoverCustomConfig\"\n (outSelectKey)=\"handlerSelectedKey($event)\"\n (outFunctionsControl)=\"handlerDropdownFunctionControl($event)\">\n <libs_ui-components-buttons-button\n [iconOnlyType]=\"true\"\n [classIconLeft]=\"'libs-ui-icon-more-vertical text-[#333333] text-[12px] {{ configDropdown.classInclude }}'\"\n [classInclude]=\"'p-[7px] libs-ui-border-general'\"\n [type]=\"'button-third'\"\n [ignoreStopPropagationEvent]=\"true\" />\n </libs_ui-components-dropdown>\n }\n @if (item.key === 'button-dropdown' && item.configButtonDropdown; as configDropdown) {\n <libs_ui-components-buttons-dropdown\n [applyNow]=\"true\"\n [label]=\"item.configButtonDropdown.label || ' '\"\n [classIconRight]=\"item.configButtonDropdown.classIconRight || ' '\"\n [classIconLeft]=\"item.configButtonDropdown.classIconLeft || ' '\"\n [typeButton]=\"item.configButtonDropdown.type || 'button-secondary'\"\n [items]=\"item.configButtonDropdown.items || []\"\n [fieldDisplay]=\"item.configButtonDropdown.fieldDisplay\"\n [popupConfig]=\"item.configButtonDropdown.popupConfig || { width: 205, maxWidth: 408, maxHeight: 48, zIndex: 100, direction: 'bottom' }\"\n (outSelectItem)=\"handlerSelectedButtonDropdownItem($event)\" />\n }\n @if (item.key === 'radio-group' && item.configRadioGroup; as configRadioGroup) {\n <libs_ui-components-radio-group\n [groups]=\"configRadioGroup\"\n [horizontal]=\"true\"\n [typeRadio]=\"'medium'\"\n [ignoreClassMarginLastItem]=\"true\"\n (outChange)=\"handlerChangeRadio($event)\" />\n }\n @if (item.key === 'tooltip-button' && item.configTooltipButton; as configTooltipButton) {\n <libs_ui-components-popover\n [type]=\"configTooltipButton.configTooltip?.type || 'other'\"\n [config]=\"configTooltipButton.configTooltip?.config\">\n <libs_ui-components-buttons-button\n [type]=\"configTooltipButton.configButton?.type || 'button-third'\"\n [classIconLeft]=\"configTooltipButton.configButton?.classIconLeft || 'libs-ui-icon-more-vertical rotate-[90deg] mr-0'\"\n [label]=\"configTooltipButton.configButton?.label || ''\"\n [iconOnlyType]=\"configTooltipButton.configButton?.iconOnlyType ?? false\"\n [popover]=\"configTooltipButton.configButton?.popover || {}\"\n (outFunctionsControl)=\"handlerFunctionControlTooltipButton($event)\"\n [ignoreStopPropagationEvent]=\"true\"\n [disable]=\"configTooltipButton.configButton?.disable ?? false\" />\n </libs_ui-components-popover>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- ===================== BODY ===================== -->\n @if (bodyConfig().getComponentOutlet; as getBodyComponentOutlet) {\n <!-- Lazy load mode: Hiển thị skeleton khi đang load, sau đó render component -->\n <div\n class=\"libs-ui-components-page_detail-body {{ bodyConfig().classInclude || '' }}\"\n LibsUiComponentsScrollOverlayDirective\n (outScroll)=\"handlerScroll($event)\">\n @let constHtmlCompBody = undefined | LibsUiPipesCallFunctionInTemplatePipe: getBodyComponentOutlet : sectionData() : null : pipeEmptyConfig | async;\n @let constHtmlInputsBody = undefined | LibsUiPipesCallFunctionInTemplatePipe: bodyConfig().getDataComponentOutlet : sectionData() : null : pipeEmptyConfig | async;\n @if (constHtmlCompBody) {\n <ng-container *ngComponentOutlet=\"constHtmlCompBody; inputs: constHtmlInputsBody\" />\n } @else {\n <libs_ui-components-skeleton [config]=\"resolvedSkeletonBody()\" />\n }\n </div>\n }\n</div>\n","import { NgTemplateOutlet } from '@angular/common';\nimport { Component, computed, input, model, OnInit, output } from '@angular/core';\nimport { IButton, LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';\nimport { LibsUiComponentsButtonsDropdownComponent } from '@libs-ui/components-buttons-dropdown';\nimport { IDropdownFunctionControlEvent, IEmitSelectKey, LibsUiComponentsDropdownComponent } from '@libs-ui/components-dropdown';\nimport { IPopoverFunctionControlEvent, LibsUiComponentsPopoverComponent, TYPE_POPOVER_EVENT } from '@libs-ui/components-popover';\nimport { LibsUiComponentsRadioGroupComponent } from '@libs-ui/components-radio-group';\nimport { IRadioEvent } from '@libs-ui/components-radio-single';\nimport { LibsUiComponentsScrollOverlayDirective } from '@libs-ui/components-scroll-overlay';\nimport { ISwitch, ISwitchEvent, LibsUiComponentsSwitchComponent } from '@libs-ui/components-switch';\nimport { LibsUiPipesEscapeHtmlPipe } from '@libs-ui/pipes-escape-html';\nimport { escapeHtml } from '@libs-ui/utils';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { IPagesTemplateDetailConfigCenter, IPagesTemplateDetailConfigRight, IPagesTemplateDetailConfigTitle } from './interfaces/config.interface';\nimport { IPageDetailFunctionControl } from './interfaces/function-control.interface';\n/**\n * @deprecated Use {@link LibsUiComponentsPagesTemplateDetailV2Component} instead.\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-pages_template-detail',\n templateUrl: './detail.component.html',\n styleUrls: ['./detail.component.scss'],\n standalone: true,\n imports: [\n TranslateModule,\n NgTemplateOutlet,\n LibsUiComponentsButtonsButtonComponent,\n LibsUiComponentsPopoverComponent,\n LibsUiComponentsRadioGroupComponent,\n LibsUiComponentsSwitchComponent,\n LibsUiComponentsDropdownComponent,\n LibsUiComponentsScrollOverlayDirective,\n LibsUiComponentsButtonsDropdownComponent,\n LibsUiPipesEscapeHtmlPipe,\n ],\n})\nexport class LibsUiComponentsPagesTemplateDetailComponent implements OnInit {\n private dropdownFunctionControl!: IDropdownFunctionControlEvent;\n protected configTitleComputed = computed(() => {\n const config = this.configTitle()?.config;\n if (!config) {\n return { content: 'i18n_back_to_list' };\n }\n\n if (!config.content) {\n config.content = 'i18n_back_to_list';\n return config;\n }\n\n return { ...config, content: escapeHtml(config.content) };\n });\n\n readonly zIndex = input<number, number | undefined>(1000, { transform: (val) => val ?? 1000 });\n readonly configRight = input<Array<IPagesTemplateDetailConfigRight>>();\n readonly configTitle = input<IPagesTemplateDetailConfigTitle>();\n readonly configCenter = input<IPagesTemplateDetailConfigCenter>();\n readonly classIncludeHeader = input<string>();\n readonly classIncludeBody = input<string>();\n readonly disable = model<boolean>(false);\n readonly isSplitHeaderRatio = input<boolean>(); // dùng khi muốn chia header làm 3 phần theo tỉ lệ 24 52 24\n\n readonly outScroll = output<Event>();\n readonly outClose = output<boolean>();\n readonly outSelectedMenuDropdown = output<IEmitSelectKey | undefined>();\n readonly outSelectedButtonDropdown = output<IEmitSelectKey>();\n readonly outFunctionControl = output<IPageDetailFunctionControl>();\n readonly outSelectedRadio = output<IRadioEvent>();\n readonly outStateDisable = output<boolean>();\n readonly outTooltipButtonFunctionControl = output<IPopoverFunctionControlEvent>();\n\n ngOnInit() {\n this.outFunctionControl.emit(this.FunctionsControl);\n }\n\n public get FunctionsControl(): IPageDetailFunctionControl {\n return {\n setStateDisable: this.setStateDisable.bind(this),\n };\n }\n\n protected handlerClickAction(event: IButton) {\n if (event?.action) {\n event.action();\n }\n }\n\n protected async handlerSwitch(event: ISwitch, swicthEvent: ISwitchEvent) {\n if (event?.action) {\n await event.action(swicthEvent);\n }\n }\n\n protected handlerClose(e: Event) {\n e.stopPropagation();\n this.outClose.emit(true);\n }\n\n protected handlerPopoverEvent(event: TYPE_POPOVER_EVENT) {\n if (event !== 'click') {\n return;\n }\n this.outClose.emit(true);\n }\n\n protected handlerSelectedKey(event?: IEmitSelectKey) {\n this.outSelectedMenuDropdown.emit(event);\n this.dropdownFunctionControl?.reset(); //lỗi chọn lần 2 (chưa reset thì keySelected chưa reset nên không chọn tiếp vào lựa chọn cũ)\n this.dropdownFunctionControl?.removeList();\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected handlerSelectedButtonDropdownItem(event: any) {\n this.outSelectedButtonDropdown.emit(event);\n }\n\n protected handlerDropdownFunctionControl(event: IDropdownFunctionControlEvent) {\n this.dropdownFunctionControl = event;\n }\n\n private async setStateDisable(stateDisable: boolean) {\n this.disable.set(stateDisable);\n this.outStateDisable.emit(this.disable());\n }\n\n protected handlerChangeRadio(event: IRadioEvent) {\n this.outSelectedRadio.emit(event);\n }\n\n protected handlerFunctionControlTooltipButton(event: IPopoverFunctionControlEvent) {\n this.outTooltipButtonFunctionControl.emit(event);\n }\n\n protected handlerScroll(event: Event) {\n this.outScroll.emit(event);\n }\n}\n","<div\n class=\"libs-ui-components-page_detail\"\n [style.zIndex]=\"zIndex()\">\n <div\n [class.row]=\"!isSplitHeaderRatio()\"\n class=\"flex items-center px-[16px] py-[8px] justify-between bg-white libs-ui-border-top-general {{ classIncludeHeader() || '' }}\">\n <div\n [class.columns-8]=\"!isSplitHeaderRatio()\"\n [class.w-[24%]]=\"isSplitHeaderRatio()\">\n <div class=\"flex items-center\">\n @if (!configTitle()?.ignoreButtonBack) {\n <i\n class=\"libs-ui-icon-chevron-right rotate-[180deg] before:text-[16px] mr-[8px] cursor-pointer text-[var(--libs-ui-color-default)]\"\n (click)=\"handlerClose($event)\"\n (keydown.enter)=\"handlerClose($event)\"></i>\n }\n <div class=\"flex w-full items-center\">\n @if (configTitle()?.isShowBackToListLabel) {\n <libs_ui-components-buttons-button\n [label]=\"'i18n_back_to_list'\"\n [classLabel]=\"'lib-ui-font-h6m'\"\n [type]=\"'button-link-primary'\"\n [classInclude]=\"'!p-0'\"\n (outClick)=\"handlerClose($event)\" />\n }\n @if (configTitle()?.config; as config) {\n <libs_ui-components-popover\n [config]=\"configTitleComputed()\"\n [type]=\"'text'\"\n [mode]=\"'hover'\"\n [classInclude]=\"'cursor-pointer ' + (config.classInclude || 'text-[var(--libs-ui-color-default)] libs-ui-font-h6m')\"\n [innerHtml]=\"config.content ? (!configTitle()?.ignoreEscapeHtml ? (config.content | LibsUiPipesEscapeHtmlPipe | translate) : (config.content | translate)) : '&mdash;'\"\n (outEvent)=\"handlerPopoverEvent($event)\" />\n }\n @if (configTitle()?.configDescription; as configDescription) {\n <libs_ui-components-popover\n [config]=\"configDescription.config\"\n [type]=\"'text'\"\n [mode]=\"'hover'\"\n [classInclude]=\"configDescription.config.classInclude || 'libs-ui-font-h6r text-[#6a7383]'\"\n [innerHtml]=\"configDescription.innerView | LibsUiPipesEscapeHtmlPipe | translate\" />\n }\n </div>\n </div>\n </div>\n @if (isSplitHeaderRatio() && configCenter(); as configCenter) {\n <div class=\"w-[52%] flex items-center justify-center px-[48px]\">\n @if (!configCenter.template) {\n <libs_ui-components-popover\n type=\"text\"\n [config]=\"{\n maxWidth: 250,\n zIndex: zIndex() + 1,\n }\"\n [classInclude]=\"configCenter.classIncludeTitle ?? 'uppercase libs-ui-font-h4s'\"\n [innerHtml]=\"configCenter.title ? (configCenter.title | translate | LibsUiPipesEscapeHtmlPipe) : '&mdash'\" />\n } @else {\n <ng-container *ngTemplateOutlet=\"configCenter.template\" />\n }\n </div>\n }\n <div\n class=\"flex justify-end items-center\"\n [class.columns-4]=\"!isSplitHeaderRatio()\"\n [class.w-[24%]]=\"isSplitHeaderRatio()\">\n @for (item of configRight(); track $index; let last = $last) {\n <div [class.mr-[12px]]=\"!last\">\n @if (item.key === 'button' && item.configButton; as configButton) {\n <libs_ui-components-buttons-button\n [label]=\"configButton.label || ''\"\n [classLabel]=\"configButton.classLabel || ''\"\n [type]=\"configButton.type || 'button-primary'\"\n [classInclude]=\"configButton.classInclude || ''\"\n [classIconLeft]=\"configButton.classIconLeft || ''\"\n [iconOnlyType]=\"configButton.iconOnlyType || false\"\n [classIconRight]=\"configButton.classIconRight || ''\"\n [popover]=\"configButton.popover || {}\"\n [disable]=\"configButton.disable || disable()\"\n [isPending]=\"configButton.isPending || false\"\n (outClick)=\"handlerClickAction(configButton)\" />\n }\n @if (item.key === 'swicth' && !item.ignoreShowButton && item.configSwicth; as configSwicth) {\n <libs_ui-components-switch\n [active]=\"configSwicth.active || false\"\n [disable]=\"configSwicth.disable || disable()\"\n (outSwitch)=\"handlerSwitch(configSwicth, $event)\" />\n }\n @if (item.key === 'menu-dropdown' && item.configDropdown; as configDropdown) {\n <libs_ui-components-dropdown\n [isNgContent]=\"true\"\n [zIndex]=\"2004\"\n [listConfig]=\"configDropdown.listConfig\"\n [listHiddenInputSearch]=\"true\"\n [popoverCustomConfig]=\"configDropdown.popoverCustomConfig\"\n (outSelectKey)=\"handlerSelectedKey($event)\"\n (outFunctionsControl)=\"handlerDropdownFunctionControl($event)\">\n <libs_ui-components-buttons-button\n [iconOnlyType]=\"true\"\n [classIconLeft]=\"'libs-ui-icon-more-vertical text-[#333333] text-[12px] {{ configDropdown.classInclude }}'\"\n [classInclude]=\"'p-[7px] libs-ui-border-general'\"\n [type]=\"'button-third'\"\n [ignoreStopPropagationEvent]=\"true\" />\n </libs_ui-components-dropdown>\n }\n @if (item.key === 'button-dropdown' && item.configButtonDropdown; as configDropdown) {\n <libs_ui-components-buttons-dropdown\n [applyNow]=\"true\"\n [label]=\"item.configButtonDropdown.label || ' '\"\n [classIconRight]=\"item.configButtonDropdown.classIconRight || ' '\"\n [classIconLeft]=\"item.configButtonDropdown.classIconLeft || ' '\"\n [typeButton]=\"item.configButtonDropdown.type || 'button-secondary'\"\n [items]=\"item.configButtonDropdown.items || []\"\n [fieldDisplay]=\"item.configButtonDropdown.fieldDisplay\"\n [popupConfig]=\"item.configButtonDropdown.popupConfig || { width: 205, maxWidth: 408, maxHeight: 48, zIndex: 100, direction: 'bottom' }\"\n (outSelectItem)=\"handlerSelectedButtonDropdownItem($event)\" />\n }\n\n @if (item.key === 'radio-group' && item.configRadioGroup; as configRadioGroup) {\n <libs_ui-components-radio-group\n [groups]=\"configRadioGroup\"\n [horizontal]=\"true\"\n [typeRadio]=\"'medium'\"\n [ignoreClassMarginLastItem]=\"true\"\n (outChange)=\"handlerChangeRadio($event)\" />\n }\n\n @if (item.key === 'tooltip-button' && item.configTooltipButton; as configTooltipButton) {\n <libs_ui-components-popover\n [type]=\"configTooltipButton.configTooltip?.type || 'other'\"\n [config]=\"configTooltipButton.configTooltip?.config\">\n <libs_ui-components-buttons-button\n [type]=\"configTooltipButton.configButton?.type || 'button-third'\"\n [classIconLeft]=\"configTooltipButton.configButton?.classIconLeft || 'libs-ui-icon-more-vertical rotate-[90deg] mr-0'\"\n [label]=\"configTooltipButton.configButton?.label || ''\"\n [iconOnlyType]=\"configTooltipButton.configButton?.iconOnlyType ?? false\"\n [popover]=\"configTooltipButton.configButton?.popover || {}\"\n (outFunctionsControl)=\"handlerFunctionControlTooltipButton($event)\"\n [ignoreStopPropagationEvent]=\"true\"\n [disable]=\"configTooltipButton.configButton?.disable ?? false\" />\n </libs_ui-components-popover>\n }\n </div>\n }\n </div>\n </div>\n\n <div\n class=\"libs-ui-components-page_detail-body {{ classIncludeBody() }}\"\n LibsUiComponentsScrollOverlayDirective\n (outScroll)=\"handlerScroll($event)\">\n <ng-content></ng-content>\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,23 +1,23 @@
1
1
  {
2
2
  "name": "@libs-ui/components-pages-template-detail",
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-buttons-dropdown": "0.2.356-42",
9
- "@libs-ui/components-dropdown": "0.2.356-42",
10
- "@libs-ui/components-popover": "0.2.356-42",
11
- "@libs-ui/components-radio-group": "0.2.356-42",
12
- "@libs-ui/components-radio-single": "0.2.356-42",
13
- "@libs-ui/components-scroll-overlay": "0.2.356-42",
14
- "@libs-ui/components-switch": "0.2.356-42",
15
- "@libs-ui/pipes-escape-html": "0.2.356-42",
16
- "@libs-ui/utils": "0.2.356-42",
7
+ "@libs-ui/components-buttons-button": "0.2.356-43",
8
+ "@libs-ui/components-buttons-dropdown": "0.2.356-43",
9
+ "@libs-ui/components-dropdown": "0.2.356-43",
10
+ "@libs-ui/components-popover": "0.2.356-43",
11
+ "@libs-ui/components-radio-group": "0.2.356-43",
12
+ "@libs-ui/components-radio-single": "0.2.356-43",
13
+ "@libs-ui/components-scroll-overlay": "0.2.356-43",
14
+ "@libs-ui/components-switch": "0.2.356-43",
15
+ "@libs-ui/pipes-escape-html": "0.2.356-43",
16
+ "@libs-ui/utils": "0.2.356-43",
17
17
  "@ngx-translate/core": "^15.0.0",
18
- "@libs-ui/interfaces-types": "0.2.356-42",
19
- "@libs-ui/components-skeleton": "0.2.356-42",
20
- "@libs-ui/pipes-call-function-in-template": "0.2.356-42"
18
+ "@libs-ui/interfaces-types": "0.2.356-43",
19
+ "@libs-ui/components-skeleton": "0.2.356-43",
20
+ "@libs-ui/pipes-call-function-in-template": "0.2.356-43"
21
21
  },
22
22
  "sideEffects": false,
23
23
  "module": "fesm2022/libs-ui-components-pages-template-detail.mjs",