@libs-ui/components-buttons-group 0.2.355-8 → 0.2.356-0
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 +438 -84
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,131 +1,485 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @libs-ui/components-buttons-group
|
|
2
|
+
|
|
3
|
+
> Component Button Group cho phép nhóm nhiều button thành một nhóm liền kề với trạng thái active.
|
|
2
4
|
|
|
3
5
|
## Giới thiệu
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
`LibsUiComponentsButtonsGroupComponent` là một standalone Angular component được thiết kế để hiển thị một nhóm các button liền kề nhau. Component hỗ trợ quản lý trạng thái active và cho phép chuyển đổi giữa các button trong nhóm.
|
|
8
|
+
|
|
9
|
+
### Tính năng
|
|
10
|
+
|
|
11
|
+
- ✅ Nhóm nhiều button thành một group liền kề
|
|
12
|
+
- ✅ Quản lý trạng thái active với visual feedback rõ ràng
|
|
13
|
+
- ✅ Two-way binding cho index button đang active
|
|
14
|
+
- ✅ Hỗ trợ disable toàn bộ group hoặc từng button
|
|
15
|
+
- ✅ Tích hợp popover cho từng button
|
|
16
|
+
- ✅ Hỗ trợ icon cho button
|
|
17
|
+
- ✅ Tự động xử lý border radius cho button đầu/cuối/giữa
|
|
18
|
+
- ✅ Angular Signals cho tính phản hồi cao
|
|
19
|
+
- ✅ OnPush Change Detection tối ưu hiệu năng
|
|
6
20
|
|
|
7
|
-
##
|
|
21
|
+
## Khi nào sử dụng
|
|
8
22
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
- Tích hợp popover control event (`outFunctionsControl`)
|
|
23
|
+
- Khi cần nhóm các button có liên quan với nhau
|
|
24
|
+
- Khi cần toggle giữa các options (như tab buttons)
|
|
25
|
+
- Khi cần hiển thị một nhóm actions liền kề
|
|
26
|
+
- Phù hợp cho filter groups, view switchers, segmented controls
|
|
14
27
|
|
|
15
28
|
## Cài đặt
|
|
16
29
|
|
|
17
30
|
```bash
|
|
31
|
+
# npm
|
|
18
32
|
npm install @libs-ui/components-buttons-group
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
hoặc
|
|
22
33
|
|
|
23
|
-
|
|
34
|
+
# yarn
|
|
24
35
|
yarn add @libs-ui/components-buttons-group
|
|
25
36
|
```
|
|
26
37
|
|
|
27
|
-
##
|
|
28
|
-
|
|
29
|
-
### Inline Template
|
|
38
|
+
## Import
|
|
30
39
|
|
|
31
40
|
```typescript
|
|
32
|
-
import { Component } from '@angular/core';
|
|
33
41
|
import { LibsUiComponentsButtonsGroupComponent } from '@libs-ui/components-buttons-group';
|
|
42
|
+
import { IButton } from '@libs-ui/components-buttons-button';
|
|
34
43
|
|
|
35
44
|
@Component({
|
|
36
|
-
selector: 'app-example',
|
|
37
45
|
standalone: true,
|
|
38
46
|
imports: [LibsUiComponentsButtonsGroupComponent],
|
|
39
|
-
|
|
40
|
-
<libs_ui-components-buttons-group
|
|
41
|
-
[buttons]="buttons"
|
|
42
|
-
[(indexActive)]="activeIndex"
|
|
43
|
-
(outChange)="onChange($event)"></libs_ui-components-buttons-group>
|
|
44
|
-
`,
|
|
47
|
+
// ...
|
|
45
48
|
})
|
|
46
|
-
export class
|
|
47
|
-
buttons = [
|
|
48
|
-
{ key: '1', label: 'Option 1' },
|
|
49
|
-
{ key: '2', label: 'Option 2' },
|
|
50
|
-
{ key: '3', label: 'Option 3' },
|
|
51
|
-
];
|
|
52
|
-
activeIndex = 0;
|
|
53
|
-
onChange(button: any) {
|
|
54
|
-
console.log('Changed:', button);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
49
|
+
export class YourComponent {}
|
|
57
50
|
```
|
|
58
51
|
|
|
59
|
-
|
|
52
|
+
## Ví dụ
|
|
53
|
+
|
|
54
|
+
### Basic Usage
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<libs_ui-components-buttons-group
|
|
58
|
+
[buttons]="viewButtons"
|
|
59
|
+
[(indexActive)]="activeIndex"
|
|
60
|
+
(outChange)="handleChange($event)" />
|
|
61
|
+
```
|
|
60
62
|
|
|
61
63
|
```typescript
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
viewButtons: IButton[] = [
|
|
65
|
+
{ label: 'List View', key: 'list' },
|
|
66
|
+
{ label: 'Grid View', key: 'grid' },
|
|
67
|
+
{ label: 'Card View', key: 'card' }
|
|
68
|
+
];
|
|
64
69
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
templateUrl: './example.component.html',
|
|
70
|
-
})
|
|
71
|
-
export class ExampleComponent {
|
|
72
|
-
buttons = [
|
|
73
|
-
/* ... */
|
|
74
|
-
];
|
|
75
|
-
activeIndex = 0;
|
|
76
|
-
onChange(button: any) {}
|
|
70
|
+
activeIndex = 0;
|
|
71
|
+
|
|
72
|
+
handleChange(button: IButton) {
|
|
73
|
+
console.log('Selected:', button);
|
|
77
74
|
}
|
|
78
75
|
```
|
|
79
76
|
|
|
77
|
+
### With Icons
|
|
78
|
+
|
|
79
|
+
```html
|
|
80
|
+
<libs_ui-components-buttons-group
|
|
81
|
+
[buttons]="viewButtonsWithIcons"
|
|
82
|
+
[(indexActive)]="activeView" />
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
viewButtonsWithIcons: IButton[] = [
|
|
87
|
+
{
|
|
88
|
+
label: 'List',
|
|
89
|
+
key: 'list',
|
|
90
|
+
classIconLeft: 'libs-ui-icon-list'
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
label: 'Grid',
|
|
94
|
+
key: 'grid',
|
|
95
|
+
classIconLeft: 'libs-ui-icon-grid'
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
label: 'Card',
|
|
99
|
+
key: 'card',
|
|
100
|
+
classIconLeft: 'libs-ui-icon-card'
|
|
101
|
+
}
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
activeView = 0;
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Icon Only Buttons
|
|
108
|
+
|
|
109
|
+
```html
|
|
110
|
+
<libs_ui-components-buttons-group
|
|
111
|
+
[buttons]="iconOnlyButtons"
|
|
112
|
+
[(indexActive)]="selectedIndex" />
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
iconOnlyButtons: IButton[] = [
|
|
117
|
+
{
|
|
118
|
+
key: 'bold',
|
|
119
|
+
classIconLeft: 'libs-ui-icon-bold',
|
|
120
|
+
iconOnlyType: true
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
key: 'italic',
|
|
124
|
+
classIconLeft: 'libs-ui-icon-italic',
|
|
125
|
+
iconOnlyType: true
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
key: 'underline',
|
|
129
|
+
classIconLeft: 'libs-ui-icon-underline',
|
|
130
|
+
iconOnlyType: true
|
|
131
|
+
}
|
|
132
|
+
];
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### With Disabled State
|
|
136
|
+
|
|
80
137
|
```html
|
|
138
|
+
<!-- Disable entire group -->
|
|
81
139
|
<libs_ui-components-buttons-group
|
|
82
140
|
[buttons]="buttons"
|
|
141
|
+
[disable]="true"
|
|
142
|
+
[(indexActive)]="activeIndex" />
|
|
143
|
+
|
|
144
|
+
<!-- Disable specific buttons -->
|
|
145
|
+
<libs_ui-components-buttons-group
|
|
146
|
+
[buttons]="buttonsWithDisabled"
|
|
147
|
+
[(indexActive)]="activeIndex" />
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
buttonsWithDisabled: IButton[] = [
|
|
152
|
+
{ label: 'Option 1', key: '1' },
|
|
153
|
+
{ label: 'Option 2', key: '2', disable: true },
|
|
154
|
+
{ label: 'Option 3', key: '3' }
|
|
155
|
+
];
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### With Popover
|
|
159
|
+
|
|
160
|
+
```html
|
|
161
|
+
<libs_ui-components-buttons-group
|
|
162
|
+
[buttons]="buttonsWithPopover"
|
|
83
163
|
[(indexActive)]="activeIndex"
|
|
84
|
-
(
|
|
164
|
+
(outFunctionsControl)="handlePopoverControl($event)" />
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
buttonsWithPopover: IButton[] = [
|
|
169
|
+
{
|
|
170
|
+
label: 'Info',
|
|
171
|
+
key: 'info',
|
|
172
|
+
popover: {
|
|
173
|
+
content: 'This is information button',
|
|
174
|
+
mode: 'hover'
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
label: 'Warning',
|
|
179
|
+
key: 'warning',
|
|
180
|
+
popover: {
|
|
181
|
+
content: 'This is warning button',
|
|
182
|
+
mode: 'hover'
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
handlePopoverControl(control: IPopoverFunctionControlEvent) {
|
|
188
|
+
console.log('Popover control:', control);
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Filter Group Example
|
|
193
|
+
|
|
194
|
+
```html
|
|
195
|
+
<libs_ui-components-buttons-group
|
|
196
|
+
[buttons]="filterButtons"
|
|
197
|
+
[(indexActive)]="activeFilter"
|
|
198
|
+
(outChange)="applyFilter($event)" />
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
filterButtons: IButton[] = [
|
|
203
|
+
{ label: 'All', key: 'all' },
|
|
204
|
+
{ label: 'Active', key: 'active' },
|
|
205
|
+
{ label: 'Completed', key: 'completed' },
|
|
206
|
+
{ label: 'Archived', key: 'archived' }
|
|
207
|
+
];
|
|
208
|
+
|
|
209
|
+
activeFilter = 0;
|
|
210
|
+
|
|
211
|
+
applyFilter(button: IButton) {
|
|
212
|
+
// Apply filter based on button.key
|
|
213
|
+
console.log('Filtering by:', button.key);
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Custom Styling
|
|
218
|
+
|
|
219
|
+
```html
|
|
220
|
+
<libs_ui-components-buttons-group
|
|
221
|
+
[buttons]="styledButtons"
|
|
222
|
+
[(indexActive)]="activeIndex" />
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
styledButtons: IButton[] = [
|
|
227
|
+
{
|
|
228
|
+
label: 'Primary',
|
|
229
|
+
key: '1',
|
|
230
|
+
classInclude: 'custom-button-class'
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
label: 'Secondary',
|
|
234
|
+
key: '2',
|
|
235
|
+
classInclude: 'custom-button-class'
|
|
236
|
+
}
|
|
237
|
+
];
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## API
|
|
241
|
+
|
|
242
|
+
### libs_ui-components-buttons-group
|
|
243
|
+
|
|
244
|
+
#### Inputs
|
|
245
|
+
|
|
246
|
+
| Property | Type | Default | Description |
|
|
247
|
+
| ----------------- | ---------------- | -------- | ---------------------------------------------- |
|
|
248
|
+
| `[buttons]` | `Array<IButton>` | required | Danh sách các button trong group |
|
|
249
|
+
| `[(indexActive)]` | `number` | `0` | Index của button đang active (two-way binding) |
|
|
250
|
+
| `[disable]` | `boolean` | `false` | Disable toàn bộ button group |
|
|
251
|
+
|
|
252
|
+
#### Outputs
|
|
253
|
+
|
|
254
|
+
| Property | Type | Description |
|
|
255
|
+
| ----------------------- | ------------------------------ | --------------------------------- |
|
|
256
|
+
| `(outChange)` | `IButton` | Emit khi chuyển đổi button active |
|
|
257
|
+
| `(outFunctionsControl)` | `IPopoverFunctionControlEvent` | Emit functions điều khiển popover |
|
|
258
|
+
|
|
259
|
+
#### Public Methods
|
|
260
|
+
|
|
261
|
+
| Method | Description |
|
|
262
|
+
| ------------------ | --------------------------------------- |
|
|
263
|
+
| `FunctionsControl` | Getter để lấy popover control functions |
|
|
264
|
+
|
|
265
|
+
## Types & Interfaces
|
|
266
|
+
|
|
267
|
+
### IButton Interface
|
|
268
|
+
|
|
269
|
+
Button group sử dụng interface `IButton` từ `@libs-ui/components-buttons-button`:
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
export interface IButton {
|
|
273
|
+
/** Unique key cho button */
|
|
274
|
+
key?: string;
|
|
275
|
+
|
|
276
|
+
/** Kiểu button (sẽ được override bởi component) */
|
|
277
|
+
type?: TYPE_BUTTON;
|
|
278
|
+
|
|
279
|
+
/** Kích thước button */
|
|
280
|
+
sizeButton?: TYPE_SIZE_BUTTON;
|
|
281
|
+
|
|
282
|
+
/** Chỉ hiển thị icon, ẩn label */
|
|
283
|
+
iconOnlyType?: boolean;
|
|
284
|
+
|
|
285
|
+
/** Label hiển thị trên button */
|
|
286
|
+
label?: string;
|
|
287
|
+
|
|
288
|
+
/** Disable button này */
|
|
289
|
+
disable?: boolean;
|
|
290
|
+
|
|
291
|
+
/** Class CSS bổ sung */
|
|
292
|
+
classInclude?: string;
|
|
293
|
+
|
|
294
|
+
/** Class icon bên trái */
|
|
295
|
+
classIconLeft?: string;
|
|
296
|
+
|
|
297
|
+
/** Class icon bên phải */
|
|
298
|
+
classIconRight?: string;
|
|
299
|
+
|
|
300
|
+
/** Class cho label */
|
|
301
|
+
classLabel?: string;
|
|
302
|
+
|
|
303
|
+
/** Cấu hình popover */
|
|
304
|
+
popover?: IPopover;
|
|
305
|
+
|
|
306
|
+
/** Không stop propagation event */
|
|
307
|
+
ignoreStopPropagationEvent?: boolean;
|
|
308
|
+
|
|
309
|
+
/** Z-index cho button */
|
|
310
|
+
zIndex?: number;
|
|
311
|
+
|
|
312
|
+
/** Trạng thái pending */
|
|
313
|
+
isPending?: boolean;
|
|
314
|
+
|
|
315
|
+
/** Action callback */
|
|
316
|
+
action?: (data?: any) => Promise<void>;
|
|
317
|
+
|
|
318
|
+
/** Style cho icon trái */
|
|
319
|
+
styleIconLeft?: Record<string, any>;
|
|
320
|
+
|
|
321
|
+
/** Style cho button */
|
|
322
|
+
styleButton?: Record<string, any>;
|
|
323
|
+
|
|
324
|
+
/** Custom color (khi type là button-custom) */
|
|
325
|
+
buttonCustom?: IColorButton;
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### TYPE_BUTTON
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
export type TYPE_BUTTON =
|
|
333
|
+
| 'button-primary'
|
|
334
|
+
| 'button-primary-revert'
|
|
335
|
+
| 'button-secondary'
|
|
336
|
+
| 'button-secondary-red'
|
|
337
|
+
| 'button-outline-secondary'
|
|
338
|
+
| 'button-third'
|
|
339
|
+
| 'button-outline'
|
|
340
|
+
| 'button-danger-high'
|
|
341
|
+
| 'button-outline-hover-danger'
|
|
342
|
+
| 'button-third-hover-danger'
|
|
343
|
+
| 'button-danger-low'
|
|
344
|
+
| 'button-green'
|
|
345
|
+
| 'button-violet'
|
|
346
|
+
| 'button-secondary-green'
|
|
347
|
+
| 'button-outline-green'
|
|
348
|
+
| 'button-custom'
|
|
349
|
+
| 'button-link-primary'
|
|
350
|
+
| 'button-link-third'
|
|
351
|
+
| 'button-link-danger-high'
|
|
352
|
+
| 'button-link-danger-low'
|
|
353
|
+
| 'button-link-green'
|
|
354
|
+
| 'button-link-violet'
|
|
355
|
+
| 'button-link-custom'
|
|
356
|
+
| string;
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### TYPE_SIZE_BUTTON
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
export type TYPE_SIZE_BUTTON = 'large' | 'medium' | 'small' | 'smaller';
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
## Styling
|
|
366
|
+
|
|
367
|
+
Component tự động xử lý styling cho button group:
|
|
368
|
+
|
|
369
|
+
- **First button**: Border radius trái (top-left, bottom-left)
|
|
370
|
+
- **Middle buttons**: Không có border radius, border-left bị loại bỏ
|
|
371
|
+
- **Last button**: Border radius phải (top-right, bottom-right), border-left bị loại bỏ
|
|
372
|
+
- **Active button**: Sử dụng `button-primary` type
|
|
373
|
+
- **Inactive buttons**: Sử dụng `button-primary-revert` type
|
|
374
|
+
|
|
375
|
+
### CSS Variables
|
|
376
|
+
|
|
377
|
+
Component sử dụng CSS variable:
|
|
378
|
+
|
|
379
|
+
```scss
|
|
380
|
+
--libs-ui-button-other-color-border: #226ff5; // Border color cho disabled state
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## Behavior
|
|
384
|
+
|
|
385
|
+
### Active State Management
|
|
386
|
+
|
|
387
|
+
- Khi click vào một button, nó sẽ trở thành active
|
|
388
|
+
- Click vào button đang active sẽ không có effect (không emit event)
|
|
389
|
+
- Index active được quản lý qua two-way binding `[(indexActive)]`
|
|
390
|
+
- Active button hiển thị với style `button-primary`
|
|
391
|
+
- Inactive buttons hiển thị với style `button-primary-revert`
|
|
392
|
+
|
|
393
|
+
### Disable Behavior
|
|
394
|
+
|
|
395
|
+
- Khi `[disable]="true"`: Toàn bộ group bị disable
|
|
396
|
+
- Khi button cụ thể có `disable: true`: Chỉ button đó bị disable
|
|
397
|
+
- Disabled buttons vẫn giữ border styling phù hợp với vị trí trong group
|
|
398
|
+
|
|
399
|
+
## Công nghệ
|
|
400
|
+
|
|
401
|
+
| Technology | Version | Purpose |
|
|
402
|
+
| --------------- | ------- | ---------------- |
|
|
403
|
+
| Angular | 18+ | Framework |
|
|
404
|
+
| Angular Signals | - | State management |
|
|
405
|
+
| SCSS | - | Styling |
|
|
406
|
+
| OnPush | - | Change Detection |
|
|
407
|
+
|
|
408
|
+
## Demo
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
npx nx serve core-ui
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
Truy cập: `http://localhost:4500/buttons/group`
|
|
415
|
+
|
|
416
|
+
## Unit Tests
|
|
417
|
+
|
|
418
|
+
```bash
|
|
419
|
+
# Chạy tests
|
|
420
|
+
npx nx test components-buttons-group
|
|
421
|
+
|
|
422
|
+
# Coverage
|
|
423
|
+
npx nx test components-buttons-group --coverage
|
|
424
|
+
|
|
425
|
+
# Watch mode
|
|
426
|
+
npx nx test components-buttons-group --watch
|
|
85
427
|
```
|
|
86
428
|
|
|
87
|
-
##
|
|
429
|
+
## Dependencies
|
|
430
|
+
|
|
431
|
+
- `@angular/core`: >=18.0.0
|
|
432
|
+
- `@libs-ui/components-buttons-button`: 0.2.355-14
|
|
433
|
+
- `@libs-ui/components-popover`: 0.2.355-14
|
|
434
|
+
- `@ngx-translate/core`: ^15.0.0
|
|
435
|
+
|
|
436
|
+
## Important Notes
|
|
437
|
+
|
|
438
|
+
### ⚠️ Type Override
|
|
439
|
+
|
|
440
|
+
Component tự động override `type` property của buttons:
|
|
441
|
+
|
|
442
|
+
- Active button → `button-primary`
|
|
443
|
+
- Inactive button → `button-primary-revert`
|
|
444
|
+
|
|
445
|
+
Nếu bạn muốn custom type, cần modify component source code.
|
|
446
|
+
|
|
447
|
+
### ⚠️ Border Styling
|
|
448
|
+
|
|
449
|
+
Component sử dụng `::ng-deep` để style nested components. Điều này cần thiết để style các button components bên trong nhưng có thể ảnh hưởng đến global styles nếu không cẩn thận.
|
|
450
|
+
|
|
451
|
+
### ⚠️ Index-based Active State
|
|
452
|
+
|
|
453
|
+
Component sử dụng index thay vì key để quản lý active state. Đảm bảo array `buttons` không thay đổi thứ tự nếu bạn muốn maintain active state.
|
|
88
454
|
|
|
89
|
-
|
|
90
|
-
- **Tailwind CSS** 3.x (phong cách demo)
|
|
455
|
+
## Best Practices
|
|
91
456
|
|
|
92
|
-
|
|
457
|
+
1. **Sử dụng key duy nhất**: Luôn cung cấp `key` unique cho mỗi button để dễ identify
|
|
458
|
+
2. **Limit số lượng buttons**: Nên giới hạn 3-5 buttons trong một group để UX tốt
|
|
459
|
+
3. **Consistent labels**: Sử dụng label ngắn gọn, rõ ràng và có độ dài tương đương
|
|
460
|
+
4. **Icon consistency**: Nếu dùng icon, nên dùng cho tất cả buttons hoặc không dùng
|
|
461
|
+
5. **Responsive design**: Cân nhắc sử dụng icon-only mode trên mobile
|
|
93
462
|
|
|
94
|
-
|
|
463
|
+
## Troubleshooting
|
|
95
464
|
|
|
96
|
-
|
|
97
|
-
| ----------- | ---------------- | -------- | --------------------------------------- |
|
|
98
|
-
| buttons | `Array<IButton>` | required | Mảng các nút sẽ hiển thị trong nhóm. |
|
|
99
|
-
| indexActive | `number` | `0` | Chỉ số của nút đang được chọn (từ 0). |
|
|
100
|
-
| disable | `boolean` | `false` | Nếu true: vô hiệu hóa toàn bộ nhóm nút. |
|
|
465
|
+
### Button không chuyển active state
|
|
101
466
|
|
|
102
|
-
|
|
467
|
+
- Kiểm tra `[(indexActive)]` binding
|
|
468
|
+
- Đảm bảo không có logic nào block event handler
|
|
469
|
+
- Verify button không bị disable
|
|
103
470
|
|
|
104
|
-
|
|
105
|
-
| ------------------- | ------------------------------ | ----------------------------------- |
|
|
106
|
-
| outChange | `(button: IButton) => void` | Trả về nút vừa được chọn. |
|
|
107
|
-
| outFunctionsControl | `IPopoverFunctionControlEvent` | Cung cấp API để điều khiển popover. |
|
|
471
|
+
### Border styling không đúng
|
|
108
472
|
|
|
109
|
-
|
|
473
|
+
- Kiểm tra ViewEncapsulation của parent component
|
|
474
|
+
- Verify CSS variables được define
|
|
475
|
+
- Check xem có CSS conflicts không
|
|
110
476
|
|
|
111
|
-
|
|
477
|
+
### Popover không hoạt động
|
|
112
478
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
| type | `TYPE_BUTTON` | no | Kiểu giao diện của nút (primary, secondary...). |
|
|
117
|
-
| sizeButton | `TYPE_SIZE_BUTTON` | no | Kích thước của nút (nhỏ, trung, lớn). |
|
|
118
|
-
| iconOnlyType | `boolean` | no | Nếu true: chỉ hiện icon, không hiện nhãn. |
|
|
119
|
-
| label | `string` | no | Văn bản hiển thị trên nút. |
|
|
120
|
-
| disable | `boolean` | no | Vô hiệu hóa nút khi true. |
|
|
121
|
-
| classInclude | `string` | no | Class CSS thêm cho container của nút. |
|
|
122
|
-
| classIconLeft | `string` | no | Class CSS thêm cho icon bên trái. |
|
|
123
|
-
| classIconRight | `string` | no | Class CSS thêm cho icon bên phải. |
|
|
124
|
-
| classLabel | `string` | no | Class CSS thêm cho nhãn. |
|
|
125
|
-
| popover | `IPopover` | no | Cấu hình popover cho nút (nếu cần). |
|
|
479
|
+
- Đảm bảo đã import `@libs-ui/components-popover`
|
|
480
|
+
- Verify popover config đúng format
|
|
481
|
+
- Check z-index conflicts
|
|
126
482
|
|
|
127
|
-
|
|
483
|
+
## License
|
|
128
484
|
|
|
129
|
-
|
|
130
|
-
| -------- | ---- | -------- | --------------------------------------------------- |
|
|
131
|
-
| ... | ... | ... | Xem `@libs-ui/components-popover` để biết chi tiết. |
|
|
485
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libs-ui/components-buttons-group",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.356-0",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"@angular/core": ">=18.0.0",
|
|
6
|
-
"@libs-ui/components-buttons-button": "0.2.
|
|
7
|
-
"@libs-ui/components-popover": "0.2.
|
|
6
|
+
"@libs-ui/components-buttons-button": "0.2.356-0",
|
|
7
|
+
"@libs-ui/components-popover": "0.2.356-0",
|
|
8
8
|
"@ngx-translate/core": "^15.0.0"
|
|
9
9
|
},
|
|
10
10
|
"sideEffects": false,
|