@libs-ui/components-card 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,189 +1,362 @@
|
|
|
1
1
|
# @libs-ui/components-card
|
|
2
2
|
|
|
3
|
-
> Component card
|
|
3
|
+
> Component card có header collapsible, hỗ trợ custom template, two-way binding và điều khiển từ bên ngoài.
|
|
4
4
|
|
|
5
5
|
## Giới thiệu
|
|
6
6
|
|
|
7
|
-
`LibsUiComponentsCardComponent` là
|
|
7
|
+
`LibsUiComponentsCardComponent` là standalone Angular component hiển thị nội dung trong container gồm header và body, với khả năng collapse/expand. Header hỗ trợ label tùy chỉnh, icon collapse (trái hoặc phải), custom template, và cho phép component cha điều khiển trạng thái thông qua `IFunctionControlCard`.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Ngoài component chính, lib còn cung cấp `LibsUiComponentsCardWrapperComponent` — wrapper đơn giản hóa API dành cho các form section có shadow và label chuẩn thiết kế.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## Tính năng
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
13
|
+
- Header có thể collapse/expand với animation icon
|
|
14
|
+
- Two-way binding trạng thái ẩn/hiện qua `model()` (`[(isHidden)]`)
|
|
15
|
+
- Custom template cho header (override label)
|
|
16
|
+
- Điều khiển card từ component cha qua `IFunctionControlCard`
|
|
17
|
+
- Cấu hình styling linh hoạt qua `IConfigCard` (border, background, icon position, class override)
|
|
18
|
+
- Sub-component `CardWrapper` với API đơn giản, shadow, border error state
|
|
19
|
+
- Standalone component, ChangeDetectionStrategy.OnPush, Angular Signals
|
|
20
20
|
|
|
21
21
|
## Khi nào sử dụng
|
|
22
22
|
|
|
23
|
-
- Hiển thị nội dung trong
|
|
24
|
-
- Cần
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
## ⚠️ Important Notes
|
|
29
|
-
|
|
30
|
-
- **clickExactly**: Khi true, chỉ click vào icon collapse mới toggle. Khi false, click vào toàn bộ header sẽ toggle.
|
|
31
|
-
- **templateHeader**: Khi sử dụng custom template header, label input sẽ bị ignore.
|
|
32
|
-
- **FunctionsControl**: Emit qua outFunctionsControl trong ngOnInit, cần lưu reference để điều khiển từ component cha.
|
|
23
|
+
- Hiển thị nội dung trong container có header và body
|
|
24
|
+
- Cần section có thể đóng/mở trong form hoặc dashboard
|
|
25
|
+
- Nhóm các trường thông tin liên quan với tiêu đề rõ ràng
|
|
26
|
+
- Form section cần border error khi có lỗi validation (dùng CardWrapper)
|
|
33
27
|
|
|
34
28
|
## Cài đặt
|
|
35
29
|
|
|
36
30
|
```bash
|
|
37
|
-
# npm
|
|
38
31
|
npm install @libs-ui/components-card
|
|
39
|
-
|
|
40
|
-
# yarn
|
|
41
|
-
yarn add @libs-ui/components-card
|
|
42
32
|
```
|
|
43
33
|
|
|
44
34
|
## Import
|
|
45
35
|
|
|
46
36
|
```typescript
|
|
47
|
-
import {
|
|
37
|
+
import {
|
|
38
|
+
LibsUiComponentsCardComponent,
|
|
39
|
+
LibsUiComponentsCardWrapperComponent,
|
|
40
|
+
IConfigCard,
|
|
41
|
+
IFunctionControlCard,
|
|
42
|
+
} from '@libs-ui/components-card';
|
|
48
43
|
|
|
49
44
|
@Component({
|
|
50
45
|
standalone: true,
|
|
51
|
-
imports: [LibsUiComponentsCardComponent],
|
|
52
|
-
// ...
|
|
46
|
+
imports: [LibsUiComponentsCardComponent, LibsUiComponentsCardWrapperComponent],
|
|
53
47
|
})
|
|
54
48
|
export class YourComponent {}
|
|
55
49
|
```
|
|
56
50
|
|
|
57
|
-
## Ví dụ
|
|
51
|
+
## Ví dụ sử dụng
|
|
58
52
|
|
|
59
|
-
###
|
|
53
|
+
### 1. Card cơ bản
|
|
60
54
|
|
|
61
55
|
```html
|
|
62
|
-
<libs_ui-components-card [label]="{ labelLeft: '
|
|
63
|
-
<p>
|
|
56
|
+
<libs_ui-components-card [label]="{ labelLeft: 'Thông tin cơ bản' }">
|
|
57
|
+
<p class="text-gray-700">Nội dung card hiển thị ở đây.</p>
|
|
64
58
|
</libs_ui-components-card>
|
|
65
59
|
```
|
|
66
60
|
|
|
67
|
-
|
|
61
|
+
```typescript
|
|
62
|
+
import { Component } from '@angular/core';
|
|
63
|
+
import { LibsUiComponentsCardComponent } from '@libs-ui/components-card';
|
|
64
|
+
|
|
65
|
+
@Component({
|
|
66
|
+
selector: 'app-example',
|
|
67
|
+
standalone: true,
|
|
68
|
+
imports: [LibsUiComponentsCardComponent],
|
|
69
|
+
templateUrl: './example.component.html',
|
|
70
|
+
})
|
|
71
|
+
export class ExampleComponent {}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. Card có nút collapse (two-way binding)
|
|
68
75
|
|
|
69
76
|
```html
|
|
70
77
|
<libs_ui-components-card
|
|
71
|
-
[label]="{ labelLeft: '
|
|
78
|
+
[label]="{ labelLeft: 'Thông tin hợp đồng', required: true }"
|
|
72
79
|
[hasCollapseBtn]="true"
|
|
73
80
|
[(isHidden)]="isCardHidden"
|
|
74
|
-
(outChangeStateShowContent)="
|
|
81
|
+
(outChangeStateShowContent)="handlerChangeState($event)">
|
|
75
82
|
<div class="p-4">
|
|
76
|
-
<p>
|
|
83
|
+
<p class="text-gray-700">Nội dung có thể ẩn/hiện.</p>
|
|
84
|
+
<p class="text-sm text-gray-500 mt-2">Trạng thái: {{ isCardHidden() ? 'Đang ẩn' : 'Đang hiện' }}</p>
|
|
77
85
|
</div>
|
|
78
86
|
</libs_ui-components-card>
|
|
79
87
|
```
|
|
80
88
|
|
|
81
89
|
```typescript
|
|
90
|
+
import { Component, signal } from '@angular/core';
|
|
91
|
+
import { LibsUiComponentsCardComponent } from '@libs-ui/components-card';
|
|
92
|
+
|
|
93
|
+
@Component({
|
|
94
|
+
selector: 'app-example',
|
|
95
|
+
standalone: true,
|
|
96
|
+
imports: [LibsUiComponentsCardComponent],
|
|
97
|
+
templateUrl: './example.component.html',
|
|
98
|
+
})
|
|
82
99
|
export class ExampleComponent {
|
|
83
|
-
isCardHidden = signal<boolean>(false);
|
|
100
|
+
protected isCardHidden = signal<boolean>(false);
|
|
84
101
|
|
|
85
|
-
|
|
86
|
-
|
|
102
|
+
protected handlerChangeState(event: Event): void {
|
|
103
|
+
event.stopPropagation();
|
|
104
|
+
// isHidden signal đã được cập nhật tự động qua two-way binding
|
|
87
105
|
}
|
|
88
106
|
}
|
|
89
107
|
```
|
|
90
108
|
|
|
91
|
-
###
|
|
109
|
+
### 3. Card với icon ở phải và custom styling
|
|
92
110
|
|
|
93
111
|
```html
|
|
94
112
|
<libs_ui-components-card
|
|
95
|
-
[label]="{ labelLeft: '
|
|
113
|
+
[label]="{ labelLeft: 'Cấu hình nâng cao' }"
|
|
96
114
|
[hasCollapseBtn]="true"
|
|
97
115
|
[configCard]="{
|
|
116
|
+
iconConRight: true,
|
|
98
117
|
ignoreBorderHeader: false,
|
|
99
118
|
ignoreBackgroundHeader: false,
|
|
100
|
-
|
|
101
|
-
classIncludeLabel: 'text-lg font-bold text-blue-600'
|
|
119
|
+
classIncludeLabel: 'libs-ui-font-h3s text-blue-600'
|
|
102
120
|
}"
|
|
103
|
-
[classIncludeBody]="'bg-gray-50
|
|
104
|
-
<div>
|
|
105
|
-
<
|
|
106
|
-
<p>Icon on the right, custom label styling, custom body background</p>
|
|
121
|
+
[classIncludeBody]="'bg-gray-50'">
|
|
122
|
+
<div class="p-4">
|
|
123
|
+
<p class="text-gray-600">Icon collapse nằm bên phải, label màu xanh.</p>
|
|
107
124
|
</div>
|
|
108
125
|
</libs_ui-components-card>
|
|
109
126
|
```
|
|
110
127
|
|
|
111
|
-
|
|
128
|
+
```typescript
|
|
129
|
+
import { Component } from '@angular/core';
|
|
130
|
+
import { LibsUiComponentsCardComponent } from '@libs-ui/components-card';
|
|
131
|
+
|
|
132
|
+
@Component({
|
|
133
|
+
selector: 'app-example',
|
|
134
|
+
standalone: true,
|
|
135
|
+
imports: [LibsUiComponentsCardComponent],
|
|
136
|
+
templateUrl: './example.component.html',
|
|
137
|
+
})
|
|
138
|
+
export class ExampleComponent {}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 4. Điều khiển card từ bên ngoài (External Control)
|
|
142
|
+
|
|
143
|
+
```html
|
|
144
|
+
<button
|
|
145
|
+
class="px-4 py-2 bg-blue-500 text-white rounded"
|
|
146
|
+
(click)="handlerToggleCard($event)">
|
|
147
|
+
Toggle Card
|
|
148
|
+
</button>
|
|
149
|
+
|
|
150
|
+
<libs_ui-components-card
|
|
151
|
+
[label]="{ labelLeft: 'Card được điều khiển từ ngoài' }"
|
|
152
|
+
[hasCollapseBtn]="true"
|
|
153
|
+
(outFunctionsControl)="handlerReceiveFunctionsControl($event)"
|
|
154
|
+
(outChangeStateShowContent)="handlerChangeState($event)">
|
|
155
|
+
<div class="p-4">
|
|
156
|
+
<p class="text-gray-700">Card này có thể toggle bằng nút bên ngoài.</p>
|
|
157
|
+
</div>
|
|
158
|
+
</libs_ui-components-card>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import { Component, signal } from '@angular/core';
|
|
163
|
+
import { LibsUiComponentsCardComponent, IFunctionControlCard } from '@libs-ui/components-card';
|
|
164
|
+
|
|
165
|
+
@Component({
|
|
166
|
+
selector: 'app-example',
|
|
167
|
+
standalone: true,
|
|
168
|
+
imports: [LibsUiComponentsCardComponent],
|
|
169
|
+
templateUrl: './example.component.html',
|
|
170
|
+
})
|
|
171
|
+
export class ExampleComponent {
|
|
172
|
+
private cardControls = signal<IFunctionControlCard | null>(null);
|
|
173
|
+
protected isCardHidden = signal<boolean>(false);
|
|
174
|
+
|
|
175
|
+
protected handlerReceiveFunctionsControl(event: Event): void {
|
|
176
|
+
event.stopPropagation();
|
|
177
|
+
this.cardControls.set(event as unknown as IFunctionControlCard);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
protected handlerToggleCard(event: Event): void {
|
|
181
|
+
event.stopPropagation();
|
|
182
|
+
this.cardControls()?.changeHidden();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
protected handlerChangeState(event: Event): void {
|
|
186
|
+
event.stopPropagation();
|
|
187
|
+
this.isCardHidden.set(event as unknown as boolean);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
> **Lưu ý:** `outFunctionsControl` emit `IFunctionControlCard` (không phải DOM Event). Binding đúng là `(outFunctionsControl)="handlerReceiveFunctionsControl($event)"` với `$event` kiểu `IFunctionControlCard`.
|
|
193
|
+
|
|
194
|
+
### 5. Card với custom template header
|
|
112
195
|
|
|
113
196
|
```html
|
|
114
|
-
<
|
|
197
|
+
<ng-template #customHeader>
|
|
198
|
+
<div class="flex items-center gap-3 w-full">
|
|
199
|
+
<span class="libs-ui-icon-settings text-blue-500"></span>
|
|
200
|
+
<span class="libs-ui-font-h3s text-gray-800">Header tùy chỉnh</span>
|
|
201
|
+
<span class="ml-auto text-xs text-gray-400">v2.0</span>
|
|
202
|
+
</div>
|
|
203
|
+
</ng-template>
|
|
115
204
|
|
|
116
205
|
<libs_ui-components-card
|
|
117
|
-
[label]="{ labelLeft: 'Externally Controlled Card' }"
|
|
118
206
|
[hasCollapseBtn]="true"
|
|
119
|
-
|
|
120
|
-
(outChangeStateShowContent)="isCardHidden = $event">
|
|
207
|
+
[templateHeader]="customHeader">
|
|
121
208
|
<div class="p-4">
|
|
122
|
-
<p>
|
|
209
|
+
<p class="text-gray-700">Nội dung với header hoàn toàn tùy chỉnh.</p>
|
|
123
210
|
</div>
|
|
124
211
|
</libs_ui-components-card>
|
|
125
212
|
```
|
|
126
213
|
|
|
127
214
|
```typescript
|
|
215
|
+
import { Component } from '@angular/core';
|
|
216
|
+
import { LibsUiComponentsCardComponent } from '@libs-ui/components-card';
|
|
217
|
+
|
|
218
|
+
@Component({
|
|
219
|
+
selector: 'app-example',
|
|
220
|
+
standalone: true,
|
|
221
|
+
imports: [LibsUiComponentsCardComponent],
|
|
222
|
+
templateUrl: './example.component.html',
|
|
223
|
+
})
|
|
224
|
+
export class ExampleComponent {}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 6. CardWrapper — API đơn giản hóa
|
|
228
|
+
|
|
229
|
+
```html
|
|
230
|
+
<libs_ui-components-card-wrapper
|
|
231
|
+
[labelConfig]="{ labelLeft: 'THÔNG TIN ĐỐI TÁC', required: true }"
|
|
232
|
+
[hasCollapseBtn]="true">
|
|
233
|
+
<div class="p-4">
|
|
234
|
+
<p class="text-gray-700">Wrapper với shadow, label tự động uppercase qua i18n.</p>
|
|
235
|
+
</div>
|
|
236
|
+
</libs_ui-components-card-wrapper>
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
import { Component } from '@angular/core';
|
|
241
|
+
import { LibsUiComponentsCardWrapperComponent } from '@libs-ui/components-card';
|
|
242
|
+
|
|
243
|
+
@Component({
|
|
244
|
+
selector: 'app-example',
|
|
245
|
+
standalone: true,
|
|
246
|
+
imports: [LibsUiComponentsCardWrapperComponent],
|
|
247
|
+
templateUrl: './example.component.html',
|
|
248
|
+
})
|
|
249
|
+
export class ExampleComponent {}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### 7. CardWrapper — trạng thái lỗi
|
|
253
|
+
|
|
254
|
+
```html
|
|
255
|
+
<libs_ui-components-card-wrapper
|
|
256
|
+
[labelConfig]="{ labelLeft: 'THÔNG TIN BẮT BUỘC', required: true }"
|
|
257
|
+
[borderError]="hasError()"
|
|
258
|
+
[hasCollapseBtn]="true">
|
|
259
|
+
<div class="p-4">
|
|
260
|
+
<p class="text-red-600">Vui lòng điền đầy đủ thông tin bắt buộc.</p>
|
|
261
|
+
</div>
|
|
262
|
+
</libs_ui-components-card-wrapper>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import { Component, signal } from '@angular/core';
|
|
267
|
+
import { LibsUiComponentsCardWrapperComponent } from '@libs-ui/components-card';
|
|
268
|
+
|
|
269
|
+
@Component({
|
|
270
|
+
selector: 'app-example',
|
|
271
|
+
standalone: true,
|
|
272
|
+
imports: [LibsUiComponentsCardWrapperComponent],
|
|
273
|
+
templateUrl: './example.component.html',
|
|
274
|
+
})
|
|
128
275
|
export class ExampleComponent {
|
|
129
|
-
|
|
130
|
-
isCardHidden = false;
|
|
276
|
+
protected hasError = signal<boolean>(true);
|
|
131
277
|
}
|
|
132
278
|
```
|
|
133
279
|
|
|
134
|
-
##
|
|
280
|
+
## @Input() — libs_ui-components-card
|
|
135
281
|
|
|
136
|
-
|
|
282
|
+
| Input | Type | Default | Mô tả | Ví dụ |
|
|
283
|
+
|---|---|---|---|---|
|
|
284
|
+
| `[(isHidden)]` | `boolean` (model) | `false` | Trạng thái ẩn/hiện content, hỗ trợ two-way binding | `[(isHidden)]="isCardHidden"` |
|
|
285
|
+
| `[classIncludeBody]` | `string` | `undefined` | Class CSS bổ sung cho phần body | `[classIncludeBody]="'bg-gray-50 p-6'"` |
|
|
286
|
+
| `[classIncludeHeader]` | `string` | `undefined` | Class CSS bổ sung cho phần header | `[classIncludeHeader]="'!p-0'"` |
|
|
287
|
+
| `[classIncludeHeaderWhenHiddenContent]` | `string` | `undefined` | Class CSS bổ sung cho header khi content đang bị ẩn | `[classIncludeHeaderWhenHiddenContent]="'rounded-[4px]'"` |
|
|
288
|
+
| `[clickExactly]` | `boolean` | `undefined` | Khi `true`: chỉ click icon collapse mới toggle; khi `false`: click toàn bộ header sẽ toggle | `[clickExactly]="true"` |
|
|
289
|
+
| `[configCard]` | `IConfigCard` | `undefined` | Cấu hình styling và behavior tổng hợp của card | `[configCard]="{ iconConRight: true }"` |
|
|
290
|
+
| `[hasCollapseBtn]` | `boolean` | `undefined` | Hiển thị nút collapse/expand | `[hasCollapseBtn]="true"` |
|
|
291
|
+
| `[ignoreTitle]` | `boolean` | `undefined` | Ẩn phần header, chỉ render body | `[ignoreTitle]="true"` |
|
|
292
|
+
| `[label]` | `ILabel` | `undefined` | Cấu hình label hiển thị trong header | `[label]="{ labelLeft: 'Tiêu đề', required: true }"` |
|
|
293
|
+
| `[templateHeader]` | `TemplateRef` | `undefined` | Custom template cho header; khi truyền vào, label bị bỏ qua | `[templateHeader]="myHeaderTpl"` |
|
|
137
294
|
|
|
138
|
-
|
|
295
|
+
## @Output() — libs_ui-components-card
|
|
139
296
|
|
|
140
|
-
|
|
|
141
|
-
|
|
142
|
-
| `
|
|
143
|
-
| `
|
|
144
|
-
| `[classIncludeHeaderWhenHiddenContent]` | `string` | `-` | Class CSS thêm vào header khi content bị ẩn |
|
|
145
|
-
| `[clickExactly]` | `boolean` | `false` | True: chỉ click icon mới toggle. False: click toàn bộ header |
|
|
146
|
-
| `[configCard]` | `IConfigCard` | `undefined` | Cấu hình styling và behavior của card |
|
|
147
|
-
| `[hasCollapseBtn]` | `boolean` | `false` | Hiển thị nút collapse/expand |
|
|
148
|
-
| `[ignoreTitle]` | `boolean` | `false` | Ẩn header, chỉ hiển thị body |
|
|
149
|
-
| `[isHidden]` | `boolean (model)` | `false` | Trạng thái ẩn/hiện content (two-way binding) |
|
|
150
|
-
| `[label]` | `ILabel` | `undefined` | Label hiển thị trong header |
|
|
151
|
-
| `[templateHeader]` | `TemplateRef` | `undefined` | Custom template cho header (override label) |
|
|
297
|
+
| Output | Type | Mô tả | Handler TS | Binding HTML |
|
|
298
|
+
|---|---|---|---|---|
|
|
299
|
+
| `(outChangeStateShowContent)` | `boolean` | Emit giá trị `isHidden` mỗi khi trạng thái ẩn/hiện thay đổi | `handlerChangeState(isHidden: boolean): void { event.stopPropagation(); this.isCardHidden.set(isHidden); }` | `(outChangeStateShowContent)="handlerChangeState($event)"` |
|
|
300
|
+
| `(outFunctionsControl)` | `IFunctionControlCard` | Emit object chứa các hàm điều khiển card; được emit một lần trong `ngOnInit` | `handlerReceiveFunctionsControl(controls: IFunctionControlCard): void { event.stopPropagation(); this.cardControls.set(controls); }` | `(outFunctionsControl)="handlerReceiveFunctionsControl($event)"` |
|
|
152
301
|
|
|
153
|
-
|
|
302
|
+
## @Input() — libs_ui-components-card-wrapper
|
|
154
303
|
|
|
155
|
-
|
|
|
156
|
-
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
304
|
+
| Input | Type | Default | Mô tả | Ví dụ |
|
|
305
|
+
|---|---|---|---|---|
|
|
306
|
+
| `[borderError]` | `boolean` | `false` | Hiển thị border đỏ trạng thái lỗi | `[borderError]="hasValidationError()"` |
|
|
307
|
+
| `[hasCollapseBtn]` | `boolean` | `true` | Hiển thị nút collapse/expand | `[hasCollapseBtn]="false"` |
|
|
308
|
+
| `[labelConfig]` | `{ labelLeft: string; required?: boolean }` | `undefined` | Cấu hình label cho wrapper; `labelLeft` sẽ được i18n translate và uppercase tự động | `[labelConfig]="{ labelLeft: 'section_title', required: true }"` |
|
|
309
|
+
| `[templateHeader]` | `TemplateRef` | `undefined` | Custom template cho header | `[templateHeader]="myHeaderTpl"` |
|
|
159
310
|
|
|
160
|
-
|
|
311
|
+
## IFunctionControlCard — Methods
|
|
161
312
|
|
|
162
|
-
| Method
|
|
163
|
-
|
|
164
|
-
| `changeHidden()
|
|
313
|
+
| Method | Signature | Mô tả |
|
|
314
|
+
|---|---|---|
|
|
315
|
+
| `changeHidden` | `() => Promise<void>` | Toggle trạng thái ẩn/hiện của card content từ bên ngoài |
|
|
165
316
|
|
|
166
317
|
## Types & Interfaces
|
|
167
318
|
|
|
319
|
+
```typescript
|
|
320
|
+
import {
|
|
321
|
+
IConfigCard,
|
|
322
|
+
IFunctionControlCard,
|
|
323
|
+
} from '@libs-ui/components-card';
|
|
324
|
+
|
|
325
|
+
import { ILabel } from '@libs-ui/components-label';
|
|
326
|
+
```
|
|
327
|
+
|
|
168
328
|
```typescript
|
|
169
329
|
interface IConfigCard {
|
|
330
|
+
/** Bỏ padding-left của header */
|
|
170
331
|
ignorePaddingLeft?: boolean;
|
|
332
|
+
/** Ẩn border header (top, left, right) */
|
|
171
333
|
ignoreBorderHeader?: boolean;
|
|
334
|
+
/** Ẩn background màu xanh nhạt của header */
|
|
172
335
|
ignoreBackgroundHeader?: boolean;
|
|
336
|
+
/** Đặt icon collapse ở bên phải thay vì bên trái */
|
|
173
337
|
iconConRight?: boolean;
|
|
338
|
+
/** Chiều rộng cố định cho vùng label */
|
|
174
339
|
width?: string;
|
|
340
|
+
/** Class CSS bổ sung cho label component */
|
|
175
341
|
classIncludeLabel?: string;
|
|
342
|
+
/** Class CSS bổ sung cho icon collapse */
|
|
176
343
|
classIconInclude?: string;
|
|
344
|
+
/** Class CSS cho icon khi content đang hiện */
|
|
177
345
|
classIconWhenShowContent?: string;
|
|
346
|
+
/** Class CSS cho icon khi content đang ẩn */
|
|
178
347
|
classIconWhenHiddenContent?: string;
|
|
348
|
+
/** Ẩn border-radius của header */
|
|
179
349
|
ignoreBorderRadiusHeader?: boolean;
|
|
350
|
+
/** Ẩn border của body */
|
|
180
351
|
ignoreBorderBody?: boolean;
|
|
181
352
|
}
|
|
182
353
|
|
|
183
354
|
interface IFunctionControlCard {
|
|
355
|
+
/** Toggle trạng thái ẩn/hiện card từ bên ngoài */
|
|
184
356
|
changeHidden: () => Promise<void>;
|
|
185
357
|
}
|
|
186
358
|
|
|
359
|
+
// ILabel được export từ @libs-ui/components-label
|
|
187
360
|
interface ILabel {
|
|
188
361
|
labelLeft?: string;
|
|
189
362
|
required?: boolean;
|
|
@@ -191,49 +364,22 @@ interface ILabel {
|
|
|
191
364
|
}
|
|
192
365
|
```
|
|
193
366
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
Cấu hình styling và behavior của card component.
|
|
197
|
-
|
|
198
|
-
### IFunctionControlCard
|
|
367
|
+
## Lưu ý quan trọng
|
|
199
368
|
|
|
200
|
-
|
|
369
|
+
⚠️ **outFunctionsControl emit một lần duy nhất**: Output này emit trong `ngOnInit`. Lưu reference ngay vào signal khi nhận được để sử dụng sau: `(outFunctionsControl)="cardControls.set($event)"`.
|
|
201
370
|
|
|
202
|
-
|
|
371
|
+
⚠️ **clickExactly ảnh hưởng hành vi click**: Khi `[clickExactly]="true"`, chỉ click trực tiếp lên icon collapse mới toggle; click lên phần còn lại của header không có tác dụng. Khi `false` hoặc không truyền, click bất kỳ vị trí nào trên header đều toggle (nếu `hasCollapseBtn` là `true`).
|
|
203
372
|
|
|
204
|
-
|
|
373
|
+
⚠️ **templateHeader override label**: Khi truyền `[templateHeader]`, input `[label]` bị bỏ qua hoàn toàn. Hai input này loại trừ nhau.
|
|
205
374
|
|
|
206
|
-
|
|
375
|
+
⚠️ **CardWrapper tự động uppercase + i18n**: `labelConfig.labelLeft` được pipe qua `translate` rồi `uppercase` trong template của wrapper. Truyền i18n key nếu có, hoặc truyền chuỗi thường — kết quả sẽ luôn viết hoa.
|
|
207
376
|
|
|
208
|
-
|
|
209
|
-
| --------------- | ------- | ---------------- |
|
|
210
|
-
| Angular | 18+ | Framework |
|
|
211
|
-
| Angular Signals | - | State management |
|
|
212
|
-
| OnPush | - | Change Detection |
|
|
377
|
+
⚠️ **isHidden là model() signal**: Hỗ trợ cú pháp two-way binding `[(isHidden)]`. Có thể dùng `[isHidden]` (one-way) hoặc `[(isHidden)]` (two-way) tùy nhu cầu.
|
|
213
378
|
|
|
214
379
|
## Demo
|
|
215
380
|
|
|
216
|
-
**Local**: [http://localhost:4500/card](http://localhost:4500/card)
|
|
217
|
-
|
|
218
381
|
```bash
|
|
219
382
|
npx nx serve core-ui
|
|
220
383
|
```
|
|
221
384
|
|
|
222
|
-
Truy cập:
|
|
223
|
-
|
|
224
|
-
## Unit Tests
|
|
225
|
-
|
|
226
|
-
```bash
|
|
227
|
-
# Chạy tests
|
|
228
|
-
npx nx test components-card
|
|
229
|
-
|
|
230
|
-
# Coverage
|
|
231
|
-
npx nx test components-card --coverage
|
|
232
|
-
|
|
233
|
-
# Watch mode
|
|
234
|
-
npx nx test components-card --watch
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
## License
|
|
238
|
-
|
|
239
|
-
MIT
|
|
385
|
+
Truy cập: http://localhost:4500/card
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { model, input, output,
|
|
2
|
+
import { model, input, output, Component, ChangeDetectionStrategy } from '@angular/core';
|
|
3
3
|
import { LibsUiComponentsLabelComponent } from '@libs-ui/components-label';
|
|
4
4
|
import { NgTemplateOutlet, UpperCasePipe } from '@angular/common';
|
|
5
5
|
import * as i1 from '@ngx-translate/core';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"libs-ui-components-card.mjs","sources":["../../../../../libs-ui/components/card/src/card.component.ts","../../../../../libs-ui/components/card/src/card.component.html","../../../../../libs-ui/components/card/src/wrapper/wrapper.component.ts","../../../../../libs-ui/components/card/src/wrapper/wrapper.component.html","../../../../../libs-ui/components/card/src/libs-ui-components-card.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, input, model, OnInit, output, TemplateRef } from '@angular/core';\nimport { ILabel, LibsUiComponentsLabelComponent } from '@libs-ui/components-label';\nimport { TYPE_TEMPLATE_REF } from '@libs-ui/interfaces-types';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { IConfigCard, IFunctionControlCard } from './interfaces/card.interface';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-card',\n templateUrl: './card.component.html',\n styleUrls: ['./card.component.scss'],\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [TranslateModule, NgTemplateOutlet, LibsUiComponentsLabelComponent],\n})\nexport class LibsUiComponentsCardComponent implements OnInit {\n // #region INPUT\n readonly isHidden = model<boolean>(false);\n readonly label = input<ILabel>();\n readonly ignoreTitle = input<boolean>();\n readonly hasCollapseBtn = input<boolean>();\n readonly clickExactly = input<boolean>();\n readonly configCard = input<IConfigCard | undefined>();\n readonly templateHeader = input<TemplateRef<TYPE_TEMPLATE_REF> | undefined>(undefined);\n readonly classIncludeBody = input<string>();\n readonly classIncludeHeader = input<string>();\n readonly classIncludeHeaderWhenHiddenContent = input<string>();\n\n // #region OUTPUT\n readonly outChangeStateShowContent = output<boolean>();\n readonly outFunctionsControl = output<IFunctionControlCard>();\n\n ngOnInit(): void {\n this.outFunctionsControl.emit(this.FunctionsControl);\n }\n\n public get FunctionsControl(): IFunctionControlCard {\n return {\n changeHidden: this.handlerHiddenOrShowByTemplateHeader.bind(this),\n };\n }\n\n /* FUNCTIONS */\n protected async handlerHiddenOrShowContent(event: Event, clickExactly: boolean) {\n event.stopPropagation();\n if (!this.hasCollapseBtn() || (this.clickExactly() && !clickExactly)) {\n return;\n }\n this.isHidden.update((value) => !value);\n\n this.outChangeStateShowContent.emit(this.isHidden());\n }\n\n private async handlerHiddenOrShowByTemplateHeader() {\n if (!this.hasCollapseBtn) {\n return;\n }\n this.isHidden.update((value) => !value);\n this.outChangeStateShowContent.emit(this.isHidden());\n }\n}\n","@if (!ignoreTitle()) {\n <div\n class=\"libs-ui-card-header {{ classIncludeHeader() }} {{ isHidden() ? classIncludeHeaderWhenHiddenContent() : '' }}\"\n tabindex=\"0\"\n [class.pl-0]=\"configCard()?.ignorePaddingLeft\"\n [class.bg-[#e9f1fe]]=\"!configCard()?.ignoreBackgroundHeader\"\n [class.libs-ui-border-top-general]=\"!configCard()?.ignoreBorderHeader\"\n [class.libs-ui-border-left-general]=\"!configCard()?.ignoreBorderHeader\"\n [class.libs-ui-border-right-general]=\"!configCard()?.ignoreBorderHeader\"\n [class.libs-ui-border-bottom-general]=\"!configCard()?.ignoreBorderHeader && isHidden()\"\n [class.rounded-[4px]]=\"!configCard()?.ignoreBorderRadiusHeader\"\n [class.cursor-pointer]=\"!clickExactly()\"\n (click)=\"handlerHiddenOrShowContent($event, false)\"\n (keydown.enter)=\"handlerHiddenOrShowContent($any($event), false)\"\n (keydown.space)=\"handlerHiddenOrShowContent($any($event), false)\">\n @if (hasCollapseBtn() && !configCard()?.iconConRight) {\n <span\n tabindex=\"0\"\n (click)=\"handlerHiddenOrShowContent($event, true)\"\n (keydown.enter)=\"handlerHiddenOrShowContent($any($event), true)\"\n (keydown.space)=\"handlerHiddenOrShowContent($any($event), true)\"\n [class]=\"\n 'cursor-pointer mr-[8px] ' +\n (configCard()?.classIconInclude ?? 'before:!text-[#6a7383] ') +\n (isHidden() ? configCard()?.classIconWhenHiddenContent || ' libs-ui-icon-chevron-right' : configCard()?.classIconWhenShowContent || ' rotate-[90deg] libs-ui-icon-chevron-right')\n \"></span>\n }\n @if (!templateHeader()) {\n <div [style.width]=\"configCard()?.width || ''\">\n <libs_ui-components-label\n [popover]=\"label()?.popover\"\n [labelLeft]=\"label()?.labelLeft\"\n [labelLeftClass]=\"configCard()?.classIncludeLabel || 'libs-ui-font-h3s cursor-pointer'\"\n [required]=\"label()?.required\"\n [classInclude]=\"'cursor-pointer !mb-0'\"\n (outLabelLeftClick)=\"handlerHiddenOrShowContent($event, true)\" />\n </div>\n }\n @if (hasCollapseBtn() && configCard()?.iconConRight) {\n <span\n tabindex=\"0\"\n [class]=\"\n 'cursor-pointer ml-auto ' +\n (configCard()?.classIconInclude ?? 'before:!text-[#6a7383] ') +\n (isHidden() ? configCard()?.classIconWhenHiddenContent || ' libs-ui-icon-chevron-right rotate-[90deg]' : configCard()?.classIconWhenShowContent || ' libs-ui-icon-chevron-right -rotate-[90deg]')\n \"\n (click)=\"handlerHiddenOrShowContent($event, true)\"\n (keydown.enter)=\"handlerHiddenOrShowContent($any($event), true)\"\n (keydown.space)=\"handlerHiddenOrShowContent($any($event), true)\"></span>\n }\n @if (templateHeader(); as templateHeader) {\n <ng-container *ngTemplateOutlet=\"templateHeader\" />\n }\n </div>\n}\n\n@if (!isHidden()) {\n <div\n class=\"libs-ui-card-body {{ classIncludeBody() }}\"\n [class.libs-ui-border-general]=\"!configCard()?.ignoreBorderBody\">\n <ng-content />\n </div>\n}\n","import { UpperCasePipe } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, input, TemplateRef } from '@angular/core';\nimport { TYPE_TEMPLATE_REF } from '@libs-ui/interfaces-types';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { LibsUiComponentsCardComponent } from '../card.component';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-card-wrapper',\n templateUrl: './wrapper.component.html',\n styles: ['.libs-ui-components-card-wrapper-node-shadow { box-shadow: 0px 4px 8px 0px rgba(0, 20, 51, 0.04), 0px 1px 1px 0px rgba(0, 20, 51, 0.02) }'],\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [LibsUiComponentsCardComponent, UpperCasePipe, TranslateModule],\n})\nexport class LibsUiComponentsCardWrapperComponent {\n // #region INPUT\n\n readonly labelConfig = input<{ labelLeft: string; required?: boolean }>();\n readonly borderError = input<boolean>(false);\n readonly templateHeader = input<TemplateRef<TYPE_TEMPLATE_REF>>();\n readonly hasCollapseBtn = input<boolean>(true);\n}\n","<div\n class=\"bg-[#ffffff] p-[16px] rounded-[8px] libs-ui-components-card-wrapper-node-shadow\"\n [class.libs-ui-border-error-general]=\"borderError()\">\n @let constHtmlLabel = labelConfig()?.labelLeft || ' ';\n <libs_ui-components-card\n [label]=\"labelConfig() ? { labelLeft: constHtmlLabel | translate | uppercase, required: labelConfig()?.required } : {}\"\n [ignoreTitle]=\"templateHeader() || labelConfig() ? false : true\"\n [configCard]=\"{\n ignoreBorderHeader: true,\n ignoreBackgroundHeader: true,\n classIncludeLabel: 'libs-ui-font-h4si !text-[#071631]',\n ignoreBorderBody: true,\n classIconInclude: '!text-[#071631] before:!text-[16px]',\n }\"\n [classIncludeHeader]=\"'!p-0'\"\n [hasCollapseBtn]=\"hasCollapseBtn()\"\n [classIncludeBody]=\"'!pb-0 ' + (labelConfig() || templateHeader() ? '' : '!p-0')\"\n [templateHeader]=\"templateHeader()\">\n <ng-content />\n </libs_ui-components-card>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;MAgBa,6BAA6B,CAAA;;AAE/B,IAAA,QAAQ,GAAG,KAAK,CAAU,KAAK,CAAC;IAChC,KAAK,GAAG,KAAK,EAAU;IACvB,WAAW,GAAG,KAAK,EAAW;IAC9B,cAAc,GAAG,KAAK,EAAW;IACjC,YAAY,GAAG,KAAK,EAAW;IAC/B,UAAU,GAAG,KAAK,EAA2B;AAC7C,IAAA,cAAc,GAAG,KAAK,CAA6C,SAAS,CAAC;IAC7E,gBAAgB,GAAG,KAAK,EAAU;IAClC,kBAAkB,GAAG,KAAK,EAAU;IACpC,mCAAmC,GAAG,KAAK,EAAU;;IAGrD,yBAAyB,GAAG,MAAM,EAAW;IAC7C,mBAAmB,GAAG,MAAM,EAAwB;IAE7D,QAAQ,GAAA;QACN,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC;IACtD;AAEA,IAAA,IAAW,gBAAgB,GAAA;QACzB,OAAO;YACL,YAAY,EAAE,IAAI,CAAC,mCAAmC,CAAC,IAAI,CAAC,IAAI,CAAC;SAClE;IACH;;AAGU,IAAA,MAAM,0BAA0B,CAAC,KAAY,EAAE,YAAqB,EAAA;QAC5E,KAAK,CAAC,eAAe,EAAE;AACvB,QAAA,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,KAAK,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,EAAE;YACpE;QACF;AACA,QAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC;QAEvC,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;IACtD;AAEQ,IAAA,MAAM,mCAAmC,GAAA;AAC/C,QAAA,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;YACxB;QACF;AACA,QAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC;QACvC,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;IACtD;wGA5CW,6BAA6B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA7B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,6BAA6B,mrDChB1C,2jGA+DA,EAAA,MAAA,EAAA,CAAA,8MAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDjDY,eAAe,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,gBAAgB,oJAAE,8BAA8B,EAAA,QAAA,EAAA,0BAAA,EAAA,MAAA,EAAA,CAAA,kBAAA,EAAA,cAAA,EAAA,WAAA,EAAA,gBAAA,EAAA,6BAAA,EAAA,SAAA,EAAA,UAAA,EAAA,aAAA,EAAA,oBAAA,EAAA,cAAA,EAAA,qBAAA,EAAA,YAAA,EAAA,iBAAA,EAAA,oBAAA,EAAA,WAAA,EAAA,YAAA,EAAA,cAAA,EAAA,eAAA,EAAA,aAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,2BAAA,EAAA,kCAAA,EAAA,eAAA,EAAA,eAAA,EAAA,qBAAA,EAAA,OAAA,EAAA,aAAA,CAAA,EAAA,OAAA,EAAA,CAAA,gBAAA,EAAA,gBAAA,EAAA,oBAAA,EAAA,mBAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;4FAEhE,6BAA6B,EAAA,UAAA,EAAA,CAAA;kBATzC,SAAS;AAEE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,yBAAyB,EAAA,UAAA,EAGvB,IAAI,EAAA,eAAA,EACC,uBAAuB,CAAC,MAAM,EAAA,OAAA,EACtC,CAAC,eAAe,EAAE,gBAAgB,EAAE,8BAA8B,CAAC,EAAA,QAAA,EAAA,2jGAAA,EAAA,MAAA,EAAA,CAAA,8MAAA,CAAA,EAAA;;;MECjE,oCAAoC,CAAA;;IAGtC,WAAW,GAAG,KAAK,EAA6C;AAChE,IAAA,WAAW,GAAG,KAAK,CAAU,KAAK,CAAC;IACnC,cAAc,GAAG,KAAK,EAAkC;AACxD,IAAA,cAAc,GAAG,KAAK,CAAU,IAAI,CAAC;wGANnC,oCAAoC,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAApC,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,oCAAoC,iqBCfjD,+8BAqBA,EAAA,MAAA,EAAA,CAAA,oGAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDRY,6BAA6B,EAAA,QAAA,EAAA,yBAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,OAAA,EAAA,aAAA,EAAA,gBAAA,EAAA,cAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,qCAAA,CAAA,EAAA,OAAA,EAAA,CAAA,gBAAA,EAAA,2BAAA,EAAA,qBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAE,aAAa,iDAAE,eAAe,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,IAAA,EAAA,WAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;4FAE5D,oCAAoC,EAAA,UAAA,EAAA,CAAA;kBAThD,SAAS;AAEE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,iCAAiC,EAAA,UAAA,EAG/B,IAAI,EAAA,eAAA,EACC,uBAAuB,CAAC,MAAM,EAAA,OAAA,EACtC,CAAC,6BAA6B,EAAE,aAAa,EAAE,eAAe,CAAC,EAAA,QAAA,EAAA,+8BAAA,EAAA,MAAA,EAAA,CAAA,oGAAA,CAAA,EAAA;;;AEb1E;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"libs-ui-components-card.mjs","sources":["../../../../../libs-ui/components/card/src/card.component.ts","../../../../../libs-ui/components/card/src/card.component.html","../../../../../libs-ui/components/card/src/wrapper/wrapper.component.ts","../../../../../libs-ui/components/card/src/wrapper/wrapper.component.html","../../../../../libs-ui/components/card/src/libs-ui-components-card.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, input, model, OnInit, output, TemplateRef } from '@angular/core';\nimport { ILabel, LibsUiComponentsLabelComponent } from '@libs-ui/components-label';\nimport { TYPE_TEMPLATE_REF } from '@libs-ui/interfaces-types';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { IConfigCard, IFunctionControlCard } from './interfaces/card.interface';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-card',\n templateUrl: './card.component.html',\n styleUrls: ['./card.component.scss'],\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [TranslateModule, NgTemplateOutlet, LibsUiComponentsLabelComponent],\n})\nexport class LibsUiComponentsCardComponent implements OnInit {\n // #region INPUT\n readonly isHidden = model<boolean>(false);\n readonly label = input<ILabel>();\n readonly ignoreTitle = input<boolean>();\n readonly hasCollapseBtn = input<boolean>();\n readonly clickExactly = input<boolean>();\n readonly configCard = input<IConfigCard | undefined>();\n readonly templateHeader = input<TemplateRef<TYPE_TEMPLATE_REF> | undefined>(undefined);\n readonly classIncludeBody = input<string>();\n readonly classIncludeHeader = input<string>();\n readonly classIncludeHeaderWhenHiddenContent = input<string>();\n\n // #region OUTPUT\n readonly outChangeStateShowContent = output<boolean>();\n readonly outFunctionsControl = output<IFunctionControlCard>();\n\n ngOnInit(): void {\n this.outFunctionsControl.emit(this.FunctionsControl);\n }\n\n public get FunctionsControl(): IFunctionControlCard {\n return {\n changeHidden: this.handlerHiddenOrShowByTemplateHeader.bind(this),\n };\n }\n\n /* FUNCTIONS */\n protected async handlerHiddenOrShowContent(event: Event, clickExactly: boolean) {\n event.stopPropagation();\n if (!this.hasCollapseBtn() || (this.clickExactly() && !clickExactly)) {\n return;\n }\n this.isHidden.update((value) => !value);\n\n this.outChangeStateShowContent.emit(this.isHidden());\n }\n\n private async handlerHiddenOrShowByTemplateHeader() {\n if (!this.hasCollapseBtn) {\n return;\n }\n this.isHidden.update((value) => !value);\n this.outChangeStateShowContent.emit(this.isHidden());\n }\n}\n","@if (!ignoreTitle()) {\n <div\n class=\"libs-ui-card-header {{ classIncludeHeader() }} {{ isHidden() ? classIncludeHeaderWhenHiddenContent() : '' }}\"\n tabindex=\"0\"\n [class.pl-0]=\"configCard()?.ignorePaddingLeft\"\n [class.bg-[#e9f1fe]]=\"!configCard()?.ignoreBackgroundHeader\"\n [class.libs-ui-border-top-general]=\"!configCard()?.ignoreBorderHeader\"\n [class.libs-ui-border-left-general]=\"!configCard()?.ignoreBorderHeader\"\n [class.libs-ui-border-right-general]=\"!configCard()?.ignoreBorderHeader\"\n [class.libs-ui-border-bottom-general]=\"!configCard()?.ignoreBorderHeader && isHidden()\"\n [class.rounded-[4px]]=\"!configCard()?.ignoreBorderRadiusHeader\"\n [class.cursor-pointer]=\"!clickExactly()\"\n (click)=\"handlerHiddenOrShowContent($event, false)\"\n (keydown.enter)=\"handlerHiddenOrShowContent($any($event), false)\"\n (keydown.space)=\"handlerHiddenOrShowContent($any($event), false)\">\n @if (hasCollapseBtn() && !configCard()?.iconConRight) {\n <span\n tabindex=\"0\"\n (click)=\"handlerHiddenOrShowContent($event, true)\"\n (keydown.enter)=\"handlerHiddenOrShowContent($any($event), true)\"\n (keydown.space)=\"handlerHiddenOrShowContent($any($event), true)\"\n [class]=\"\n 'cursor-pointer mr-[8px] ' +\n (configCard()?.classIconInclude ?? 'before:!text-[#6a7383] ') +\n (isHidden() ? configCard()?.classIconWhenHiddenContent || ' libs-ui-icon-chevron-right' : configCard()?.classIconWhenShowContent || ' rotate-[90deg] libs-ui-icon-chevron-right')\n \"></span>\n }\n @if (!templateHeader()) {\n <div [style.width]=\"configCard()?.width || ''\">\n <libs_ui-components-label\n [popover]=\"label()?.popover\"\n [labelLeft]=\"label()?.labelLeft\"\n [labelLeftClass]=\"configCard()?.classIncludeLabel || 'libs-ui-font-h3s cursor-pointer'\"\n [required]=\"label()?.required\"\n [classInclude]=\"'cursor-pointer !mb-0'\"\n (outLabelLeftClick)=\"handlerHiddenOrShowContent($event, true)\" />\n </div>\n }\n @if (hasCollapseBtn() && configCard()?.iconConRight) {\n <span\n tabindex=\"0\"\n [class]=\"\n 'cursor-pointer ml-auto ' +\n (configCard()?.classIconInclude ?? 'before:!text-[#6a7383] ') +\n (isHidden() ? configCard()?.classIconWhenHiddenContent || ' libs-ui-icon-chevron-right rotate-[90deg]' : configCard()?.classIconWhenShowContent || ' libs-ui-icon-chevron-right -rotate-[90deg]')\n \"\n (click)=\"handlerHiddenOrShowContent($event, true)\"\n (keydown.enter)=\"handlerHiddenOrShowContent($any($event), true)\"\n (keydown.space)=\"handlerHiddenOrShowContent($any($event), true)\"></span>\n }\n @if (templateHeader(); as templateHeader) {\n <ng-container *ngTemplateOutlet=\"templateHeader\" />\n }\n </div>\n}\n\n@if (!isHidden()) {\n <div\n class=\"libs-ui-card-body {{ classIncludeBody() }}\"\n [class.libs-ui-border-general]=\"!configCard()?.ignoreBorderBody\">\n <ng-content />\n </div>\n}\n","import { UpperCasePipe } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, input, TemplateRef } from '@angular/core';\nimport { TYPE_TEMPLATE_REF } from '@libs-ui/interfaces-types';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { LibsUiComponentsCardComponent } from '../card.component';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-card-wrapper',\n templateUrl: './wrapper.component.html',\n styles: ['.libs-ui-components-card-wrapper-node-shadow { box-shadow: 0px 4px 8px 0px rgba(0, 20, 51, 0.04), 0px 1px 1px 0px rgba(0, 20, 51, 0.02) }'],\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [LibsUiComponentsCardComponent, UpperCasePipe, TranslateModule],\n})\nexport class LibsUiComponentsCardWrapperComponent {\n // #region INPUT\n\n readonly labelConfig = input<{ labelLeft: string; required?: boolean }>();\n readonly borderError = input<boolean>(false);\n readonly templateHeader = input<TemplateRef<TYPE_TEMPLATE_REF>>();\n readonly hasCollapseBtn = input<boolean>(true);\n}\n","<div\n class=\"bg-[#ffffff] p-[16px] rounded-[8px] libs-ui-components-card-wrapper-node-shadow\"\n [class.libs-ui-border-error-general]=\"borderError()\">\n @let constHtmlLabel = labelConfig()?.labelLeft || ' ';\n <libs_ui-components-card\n [label]=\"labelConfig() ? { labelLeft: constHtmlLabel | translate | uppercase, required: labelConfig()?.required } : {}\"\n [ignoreTitle]=\"templateHeader() || labelConfig() ? false : true\"\n [configCard]=\"{\n ignoreBorderHeader: true,\n ignoreBackgroundHeader: true,\n classIncludeLabel: 'libs-ui-font-h4si !text-[#071631]',\n ignoreBorderBody: true,\n classIconInclude: '!text-[#071631] before:!text-[16px]',\n }\"\n [classIncludeHeader]=\"'!p-0'\"\n [hasCollapseBtn]=\"hasCollapseBtn()\"\n [classIncludeBody]=\"'!pb-0 ' + (labelConfig() || templateHeader() ? '' : '!p-0')\"\n [templateHeader]=\"templateHeader()\">\n <ng-content />\n </libs_ui-components-card>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libs-ui/components-card",
|
|
3
|
-
"version": "0.2.356-
|
|
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-label": "0.2.356-
|
|
8
|
-
"@libs-ui/interfaces-types": "0.2.356-
|
|
7
|
+
"@libs-ui/components-label": "0.2.356-43",
|
|
8
|
+
"@libs-ui/interfaces-types": "0.2.356-43",
|
|
9
9
|
"@ngx-translate/core": "^15.0.0"
|
|
10
10
|
},
|
|
11
11
|
"sideEffects": false,
|