# @libs-ui/components-buttons-button

> Component Button đa năng với nhiều kiểu dáng, kích thước, icon và tích hợp popover/spinner.

## Giới thiệu

`LibsUiComponentsButtonsButtonComponent` là một Angular Standalone Component được thiết kế để hiển thị nút bấm với đầy đủ tính năng: hỗ trợ 20+ kiểu màu sắc (primary, secondary, outline, danger, link...), 4 kích thước, loading spinner tích hợp, icon trái/phải, chế độ icon-only, custom color qua `buttonCustom`, và tích hợp Popover. Component sử dụng Angular Signals + `ChangeDetectionStrategy.OnPush` để tối ưu hiệu năng.

## Tính năng

- ✅ 20+ kiểu button: primary, secondary, third, outline, danger, green, violet, link và các biến thể
- ✅ 4 kích thước: `large`, `medium`, `small`, `smaller`
- ✅ Loading state với spinner tích hợp (`isPending`)
- ✅ Icon trái (`classIconLeft`), icon phải (`classIconRight`) hoặc icon-only (`iconOnlyType`)
- ✅ Hình ảnh bên trái (`imageLeft`)
- ✅ Custom color thông qua `buttonCustom` (khi `type = 'button-custom'` hoặc `'button-link-custom'`)
- ✅ Tích hợp Popover (hover/click) với đầy đủ control API
- ✅ Trạng thái disabled với ngăn pointer events tùy chọn
- ✅ Trạng thái active (`isActive`)
- ✅ Hỗ trợ Enter key trên document (`isHandlerEnterDocumentClickButton`)
- ✅ Angular Signals + `ChangeDetectionStrategy.OnPush`
- ✅ Standalone Component, không cần NgModule

## Khi nào sử dụng

- Khi cần nút bấm để kích hoạt hành động (submit form, mở dialog, điều hướng...)
- Khi cần hiển thị trạng thái loading trong lúc xử lý async operation
- Khi cần button với popover tooltip hoặc menu dropdown
- Khi cần button chỉ có icon, không có label
- Khi cần tùy chỉnh màu sắc button theo brand riêng của feature

## Cài đặt

```bash
npm install @libs-ui/components-buttons-button
```

## Import

```typescript
import {
  LibsUiComponentsButtonsButtonComponent,
  IButton,
  TYPE_BUTTON,
  TYPE_SIZE_BUTTON,
} from '@libs-ui/components-buttons-button';

@Component({
  standalone: true,
  imports: [LibsUiComponentsButtonsButtonComponent],
  // ...
})
export class YourComponent {}
```

## Ví dụ sử dụng

### Basic — Nút bấm đơn giản

```html
<libs_ui-components-buttons-button
  label="Lưu"
  (outClick)="handlerSave($event)" />
```

```typescript
import { Component } from '@angular/core';
import { LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [LibsUiComponentsButtonsButtonComponent],
  templateUrl: './example.component.html',
})
export class ExampleComponent {
  handlerSave(event: Event): void {
    event.stopPropagation();
    // xử lý lưu dữ liệu
  }
}
```

### Button Types — Các kiểu màu sắc

```html
<!-- Solid buttons -->
<libs_ui-components-buttons-button type="button-primary"    label="Primary"    (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button type="button-secondary"  label="Secondary"  (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button type="button-third"      label="Third"      (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button type="button-outline"    label="Outline"    (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button type="button-danger-high" label="Danger"   (outClick)="handlerDelete($event)" />
<libs_ui-components-buttons-button type="button-danger-low"  label="Cảnh báo" (outClick)="handlerWarning($event)" />
<libs_ui-components-buttons-button type="button-green"      label="Xác nhận"  (outClick)="handlerConfirm($event)" />
<libs_ui-components-buttons-button type="button-violet"     label="Violet"    (outClick)="handlerClick($event)" />

<!-- Outline variants -->
<libs_ui-components-buttons-button type="button-outline-secondary"     label="Outline Secondary" (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button type="button-outline-green"         label="Outline Green"     (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button type="button-outline-hover-danger"  label="Hover Danger"      (outClick)="handlerClick($event)" />

<!-- Link style buttons -->
<libs_ui-components-buttons-button type="button-link-primary"      label="Xem thêm"  (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button type="button-link-danger-high"  label="Xóa"       (outClick)="handlerDelete($event)" />
<libs_ui-components-buttons-button type="button-link-green"        label="Xác nhận"  (outClick)="handlerClick($event)" />
```

### Button Sizes — Các kích thước

```html
<libs_ui-components-buttons-button [sizeButton]="'large'"   label="Large Button"   (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button [sizeButton]="'medium'"  label="Medium Button"  (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button [sizeButton]="'small'"   label="Small Button"   (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button [sizeButton]="'smaller'" label="Smaller Button" (outClick)="handlerClick($event)" />
```

### Loading State — Trạng thái loading

```html
<libs_ui-components-buttons-button
  label="Lưu thông tin"
  [isPending]="isSaving()"
  (outClick)="handlerSave($event)" />
```

```typescript
import { Component, signal } from '@angular/core';
import { LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';

@Component({
  selector: 'app-form',
  standalone: true,
  imports: [LibsUiComponentsButtonsButtonComponent],
  templateUrl: './form.component.html',
})
export class FormComponent {
  protected isSaving = signal(false);

  handlerSave(event: Event): void {
    event.stopPropagation();
    this.isSaving.set(true);
    // gọi API...
    // sau khi xong: this.isSaving.set(false);
  }
}
```

### With Icons — Button kèm icon

```html
<!-- Icon bên trái -->
<libs_ui-components-buttons-button
  label="Thêm mới"
  [classIconLeft]="'libs-ui-icon-add'"
  (outClick)="handlerAdd($event)" />

<!-- Icon bên phải -->
<libs_ui-components-buttons-button
  label="Tiếp theo"
  [classIconRight]="'libs-ui-icon-arrow-right'"
  (outClick)="handlerNext($event)" />

<!-- Cả hai icon -->
<libs_ui-components-buttons-button
  label="Tải xuống"
  [classIconLeft]="'libs-ui-icon-download-outline'"
  [classIconRight]="'libs-ui-icon-arrow-down'"
  (outClick)="handlerDownload($event)" />

<!-- Chỉ icon, không label -->
<libs_ui-components-buttons-button
  [classIconLeft]="'libs-ui-icon-arrange'"
  [iconOnlyType]="true"
  (outClick)="handlerOpenSettings($event)" />
```

### Disabled State — Trạng thái vô hiệu hóa

```html
<libs_ui-components-buttons-button
  label="Không thể bấm"
  [disable]="true"
  (outClick)="handlerClick($event)" />

<!-- Disable nhưng vẫn nhận pointer events (để show tooltip) -->
<libs_ui-components-buttons-button
  label="Disabled nhưng có tooltip"
  [disable]="true"
  [ignorePointerEvent]="true"
  (outClick)="handlerClick($event)" />
```

### Custom Color — Màu tùy chỉnh

`buttonCustom` (kiểu `IColorButton`) **bắt buộc** khi `type="button-custom"` (nền đặc) hoặc `type="button-link-custom"` (dạng link — nền/viền trong suốt). `configStepColor` khai báo màu cho từng trạng thái: `text` / `text_hover` / `text_active` / `text_disable` (bắt buộc) và `background*` / `border*` (tùy chọn). Mỗi giá trị nhận `string` (mã màu, `'transparent'`) hoặc `number` (step màu suy ra từ `rootColor`).

```html
<!-- Nền đặc: type="button-custom" -->
<libs_ui-components-buttons-button
  type="button-custom"
  label="Custom màu tím"
  [buttonCustom]="customPurple"
  (outClick)="handlerClick($event)" />

<!-- Dạng link: type="button-link-custom" -->
<libs_ui-components-buttons-button
  type="button-link-custom"
  label="Custom link teal"
  [buttonCustom]="customTeal"
  (outClick)="handlerClick($event)" />
```

```typescript
import { Component } from '@angular/core';
import { LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';
import { IColorButton } from '@libs-ui/services-config-project';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [LibsUiComponentsButtonsButtonComponent],
  templateUrl: './example.component.html',
})
export class ExampleComponent {
  // Nền đặc
  protected readonly customPurple: IColorButton = {
    rootColor: '#7C3AED',
    configStepColor: {
      text: '#ffffff', text_hover: '#ffffff', text_active: '#ffffff', text_disable: '#C4B5FD',
      background: '#7C3AED', background_hover: '#6D28D9', background_active: '#5B21B6', background_disable: '#DDD6FE',
      border: '#7C3AED', border_hover: '#6D28D9', border_active: '#5B21B6', border_disable: '#DDD6FE',
    },
  };

  // Dạng link — nền/viền trong suốt, chỉ đổi màu chữ
  protected readonly customTeal: IColorButton = {
    rootColor: '#0D9488',
    configStepColor: {
      text: '#0D9488', text_hover: '#0F766E', text_active: '#115E59', text_disable: '#99F6E4',
      background: 'transparent', background_hover: '#F0FDFA', background_active: '#CCFBF1', background_disable: 'transparent',
      border: 'transparent', border_hover: 'transparent', border_active: 'transparent', border_disable: 'transparent',
    },
  };

  handlerClick(event: Event): void {
    event.stopPropagation();
  }
}
```

### With Popover — Button kèm popover/tooltip

```html
<libs_ui-components-buttons-button
  label="Hover để xem tooltip"
  [popover]="{
    type: 'text',
    mode: 'hover',
    config: {
      content: 'Đây là tooltip giải thích chức năng',
      width: 220
    }
  }"
  (outClick)="handlerClick($event)"
  (outPopoverEvent)="handlerPopoverEvent($event)" />
```

```typescript
import { Component } from '@angular/core';
import { LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';
import { TYPE_POPOVER_EVENT } from '@libs-ui/components-popover';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [LibsUiComponentsButtonsButtonComponent],
  templateUrl: './example.component.html',
})
export class ExampleComponent {
  handlerClick(event: Event): void {
    event.stopPropagation();
  }

  handlerPopoverEvent(event: TYPE_POPOVER_EVENT): void {
    event.stopPropagation?.();
    // event: 'show' | 'hide' | 'click' | 'remove'
  }
}
```

### Image Left — Button kèm hình ảnh

```html
<libs_ui-components-buttons-button
  label="Đăng nhập với Google"
  [imageLeft]="{ src: '/assets/icons/google.svg', classInclude: 'mr-[8px] w-[16px] h-[16px]' }"
  (outClick)="handlerLoginWithGoogle($event)" />
```

### Active State — Trạng thái đang được chọn

```html
<libs_ui-components-buttons-button
  type="button-outline"
  label="Tab đang chọn"
  [isActive]="true"
  (outClick)="handlerSelect($event)" />
```

### Class Include — Thêm class tùy chỉnh

```html
<libs_ui-components-buttons-button
  label="Button full-width"
  classInclude="w-full justify-center"
  (outClick)="handlerClick($event)" />
```

### Enter Key Handler — Kích hoạt bằng phím Enter

```html
<!-- Button sẽ được click khi user nhấn Enter trên document -->
<libs_ui-components-buttons-button
  label="Xác nhận"
  [isHandlerEnterDocumentClickButton]="true"
  (outClick)="handlerConfirm($event)" />
```

### ViewChild — Truy cập Popover Control

```typescript
import { Component, viewChild } from '@angular/core';
import {
  LibsUiComponentsButtonsButtonComponent,
  IPopoverFunctionControlEvent,
} from '@libs-ui/components-buttons-button';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [LibsUiComponentsButtonsButtonComponent],
  template: `
    <libs_ui-components-buttons-button
      #myBtn
      label="Click"
      (outFunctionsControl)="handlerFunctionsControl($event)"
      (outClick)="handlerClick($event)" />
  `,
})
export class ExampleComponent {
  private readonly myBtn = viewChild<LibsUiComponentsButtonsButtonComponent>('myBtn');

  handlerClick(event: Event): void {
    event.stopPropagation();
    // truy cập popover control qua FunctionsControl getter
    const control = this.myBtn()?.FunctionsControl;
    control?.hide?.();
  }

  handlerFunctionsControl(control: IPopoverFunctionControlEvent): void {
    // lưu control để điều khiển popover từ bên ngoài
  }
}
```

## @Input()

| Input | Type | Default | Mô tả | Ví dụ |
|---|---|---|---|---|
| `[buttonCustom]` | `IColorButton` | `undefined` | Cấu hình màu custom — bắt buộc khi `type` là `'button-custom'` hoặc `'button-link-custom'`. Xem ví dụ "Custom Color" phía trên. | `[buttonCustom]="customPurple"` |
| `[classIconLeft]` | `string` | `''` | Class CSS của icon hiển thị bên trái label | `[classIconLeft]="'libs-ui-icon-add'"` |
| `[classIconRight]` | `string` | `''` | Class CSS của icon hiển thị bên phải label | `[classIconRight]="'libs-ui-icon-arrow-right'"` |
| `[classInclude]` | `string` | `''` | Class CSS bổ sung gắn vào phần tử button | `classInclude="w-full"` |
| `[classLabel]` | `string` | `''` | Class CSS bổ sung cho phần tử label bên trong | `[classLabel]="'font-bold'"` |
| `[disable]` | `boolean` | `false` | Vô hiệu hóa button, ngăn click và áp dụng style disabled | `[disable]="isFormInvalid()"` |
| `[flagMouse]` | `IFlagMouse` | `{ isMouseEnter: false, isMouseEnterContent: false, isContainerHasScroll: false }` | Trạng thái con trỏ chuột từ container cha để popover hoạt động đúng khi scroll | `[flagMouse]="flagMouse()"` |
| `[iconOnlyType]` | `boolean` | `false` | Chỉ hiển thị icon, ẩn hoàn toàn label | `[iconOnlyType]="true"` |
| `[ignoreFocusWhenInputTab]` | `boolean` | `undefined` | Đặt `tabindex="-1"` để button không nhận focus khi nhấn phím Tab | `[ignoreFocusWhenInputTab]="true"` |
| `[ignorePointerEvent]` | `boolean` | `undefined` | Khi `disable=true`, vẫn cho phép pointer events (hữu ích khi cần show tooltip khi disabled) | `[ignorePointerEvent]="true"` |
| `[ignoreSetClickWhenShowPopover]` | `boolean` | `undefined` | Không set trạng thái `isClick=true` khi popover mở | `[ignoreSetClickWhenShowPopover]="true"` |
| `[ignoreStopPropagationEvent]` | `boolean` | `true` | Khi `false`, gọi `event.stopPropagation()` bên trong handler click của button | `[ignoreStopPropagationEvent]="false"` |
| `[imageLeft]` | `{ src: string; classInclude?: string }` | `undefined` | Hiển thị hình ảnh bên trái label | `[imageLeft]="{ src: '/assets/google.svg', classInclude: 'mr-[8px]' }"` |
| `[isActive]` | `boolean` | `undefined` | Áp dụng trạng thái active lên button (thêm attribute `active`) | `[isActive]="isSelected()"` |
| `[isHandlerEnterDocumentClickButton]` | `boolean` | `undefined` | Lắng nghe sự kiện `keyup Enter` trên `document` và trigger click button | `[isHandlerEnterDocumentClickButton]="true"` |
| `[isPending]` | `boolean` | `undefined` | Hiển thị spinner loading, tạm thời chặn click khi đang pending | `[isPending]="isLoading()"` |
| `[label]` | `string` | `' '` | Nội dung text hiển thị trên button, hỗ trợ i18n key | `label="Lưu"` hoặc `label="i18n_save"` |
| `[popover]` | `IPopover` | `{}` | Cấu hình popover tích hợp (type, mode, config...) | `[popover]="{ type: 'text', mode: 'hover', config: { content: 'Tooltip' } }"` |
| `[sizeButton]` | `TYPE_SIZE_BUTTON` | `'medium'` | Kích thước button: `'large'`, `'medium'`, `'small'`, `'smaller'` | `[sizeButton]="'small'"` |
| `[styleButton]` | `Record<string, any>` | `undefined` | Inline styles trực tiếp cho phần tử `<button>` | `[styleButton]="{ minWidth: '120px' }"` |
| `[styleIconLeft]` | `Record<string, any>` | `undefined` | Inline styles cho icon bên trái | `[styleIconLeft]="{ fontSize: '18px' }"` |
| `[type]` | `TYPE_BUTTON` | `'button-primary'` | Kiểu button xác định màu sắc và style tổng thể | `type="button-secondary"` |
| `[widthLabelPopover]` | `number` | `undefined` | Chiều rộng (px) của popover hiển thị khi label bị truncate | `[widthLabelPopover]="200"` |
| `[zIndex]` | `number` | `10` | Z-index của popover tích hợp | `[zIndex]="100"` |

## @Output()

| Output | Type | Mô tả | Handler TS | Binding HTML |
|---|---|---|---|---|
| `(outClick)` | `Event` | Phát ra khi button được click và không bị disabled/pending | `handlerClick(event: Event): void { event.stopPropagation(); /* xử lý */ }` | `(outClick)="handlerClick($event)"` |
| `(outFunctionsControl)` | `IPopoverFunctionControlEvent` | Phát ra object chứa các hàm điều khiển popover (show, hide...) sau khi popover khởi tạo xong | `handlerFunctionsControl(ctrl: IPopoverFunctionControlEvent): void { event.stopPropagation?.(); this.popoverControl = ctrl; }` | `(outFunctionsControl)="handlerFunctionsControl($event)"` |
| `(outPopoverEvent)` | `TYPE_POPOVER_EVENT` | Phát ra các sự kiện lifecycle của popover: `'show'`, `'hide'`, `'click'`, `'remove'` | `handlerPopoverEvent(event: TYPE_POPOVER_EVENT): void { /* xử lý */ }` | `(outPopoverEvent)="handlerPopoverEvent($event)"` |

## Public Getter (FunctionsControl)

Truy cập qua `viewChild` để điều khiển popover từ bên ngoài component:

```typescript
private readonly buttonRef = viewChild<LibsUiComponentsButtonsButtonComponent>('buttonRef');

// Trong template:
// <libs_ui-components-buttons-button #buttonRef ... />

// Trong TS:
const control = this.buttonRef()?.FunctionsControl;
control?.hide?.();   // ẩn popover
control?.show?.();   // hiện popover
```

## Types & Interfaces

```typescript
import {
  IButton,
  TYPE_BUTTON,
  TYPE_SIZE_BUTTON,
} from '@libs-ui/components-buttons-button';
```

### TYPE_BUTTON

```typescript
export type TYPE_BUTTON =
  // Solid buttons
  | 'button-primary'           // Nút chính màu xanh lam
  | 'button-primary-revert'    // Biến thể revert của primary
  | 'button-secondary'         // Nút phụ
  | 'button-secondary-red'     // Nút phụ màu đỏ
  | 'button-secondary-green'   // Nút phụ màu xanh lá
  | 'button-third'             // Nút cấp 3 (ít nổi bật hơn)
  | 'button-outline'           // Nút viền
  | 'button-outline-secondary' // Nút viền secondary
  | 'button-outline-green'     // Nút viền xanh lá
  | 'button-outline-hover-danger' // Nút viền, hover chuyển đỏ
  | 'button-third-hover-danger'   // Nút third, hover chuyển đỏ
  | 'button-danger-high'       // Nút nguy hiểm cao (đỏ đậm)
  | 'button-danger-low'        // Nút nguy hiểm thấp (đỏ nhạt)
  | 'button-green'             // Nút xanh lá (thành công)
  | 'button-violet'            // Nút tím
  | 'button-custom'            // Màu tùy chỉnh — bắt buộc truyền [buttonCustom]
  // Link-style buttons (không có nền, dạng text link)
  | 'button-link-primary'
  | 'button-link-third'
  | 'button-link-danger-high'
  | 'button-link-danger-low'
  | 'button-link-green'
  | 'button-link-violet'
  | 'button-link-custom'       // Link màu tùy chỉnh — bắt buộc truyền [buttonCustom]
  | string;                    // Hỗ trợ type tùy chỉnh mở rộng
```

### TYPE_SIZE_BUTTON

```typescript
export type TYPE_SIZE_BUTTON = 'large' | 'medium' | 'small' | 'smaller';
```

### IButton

Interface dùng để cấu hình button trong danh sách (ví dụ: toolbar actions, button group):

```typescript
import { IButton } from '@libs-ui/components-buttons-button';
import { IColorButton } from '@libs-ui/services-config-project';
import { IPopover } from '@libs-ui/components-popover';

export interface IButton {
  key?: string;
  type?: TYPE_BUTTON;
  sizeButton?: TYPE_SIZE_BUTTON;
  iconOnlyType?: boolean;
  label?: string;
  disable?: boolean;
  classInclude?: string;
  classIconLeft?: string;
  classIconRight?: string;
  classLabel?: string;
  popover?: IPopover;
  ignoreStopPropagationEvent?: boolean;
  zIndex?: number;
  isPending?: boolean;
  action?: (data?: any) => Promise<void>;
  styleIconLeft?: Record<string, any>;
  styleButton?: Record<string, any>;
  buttonCustom?: IColorButton;
}
```

Ví dụ sử dụng `IButton` để cấu hình danh sách toolbar:

```typescript
import { Component } from '@angular/core';
import {
  LibsUiComponentsButtonsButtonComponent,
  IButton,
} from '@libs-ui/components-buttons-button';

@Component({
  selector: 'app-toolbar',
  standalone: true,
  imports: [LibsUiComponentsButtonsButtonComponent],
  template: `
    @for (btn of toolbarButtons; track btn.key) {
      <libs_ui-components-buttons-button
        [type]="btn.type || 'button-primary'"
        [label]="btn.label || ''"
        [classIconLeft]="btn.classIconLeft || ''"
        [disable]="btn.disable || false"
        (outClick)="handlerToolbarAction($event, btn)" />
    }
  `,
})
export class ToolbarComponent {
  protected readonly toolbarButtons: IButton[] = [
    { key: 'save',   type: 'button-primary',  label: 'Lưu',  classIconLeft: 'libs-ui-icon-download-outline' },
    { key: 'cancel', type: 'button-secondary', label: 'Hủy' },
    { key: 'delete', type: 'button-danger-high', label: 'Xóa', classIconLeft: 'libs-ui-icon-remove' },
  ];

  handlerToolbarAction(event: Event, btn: IButton): void {
    event.stopPropagation();
    btn.action?.();
  }
}
```

## Lưu ý quan trọng

⚠️ **`buttonCustom` bắt buộc với custom type**: Khi `type="button-custom"` hoặc `type="button-link-custom"`, bắt buộc phải truyền `[buttonCustom]` với `rootColor` và `configStepColor`. Thiếu config này sẽ khiến button không hiển thị màu sắc.

⚠️ **`ignoreStopPropagationEvent` mặc định là `true`**: Mặc định button KHÔNG gọi `event.stopPropagation()`. Nếu muốn chặn event lan ra container cha, set `[ignoreStopPropagationEvent]="false"`. Trong handler `(outClick)` phía consumer, nên tự gọi `event.stopPropagation()` để chắc chắn.

⚠️ **`isHandlerEnterDocumentClickButton` listener global**: Input này đăng ký `keyup` listener trên toàn bộ `document`. Chỉ dùng cho button duy nhất trong context cần xác nhận bằng Enter (ví dụ: nút OK trong dialog confirm). Không bật đồng thời nhiều button với flag này.

⚠️ **`isPending` chặn click**: Khi `isPending=true`, button hiển thị spinner và tự động bỏ qua mọi sự kiện click — không cần thêm `[disable]`.

⚠️ **`iconOnlyType` ẩn label hoàn toàn**: Khi `iconOnlyType=true`, label sẽ không được render dù có truyền `label`. Cần truyền ít nhất `classIconLeft` hoặc `classIconRight`.

⚠️ **Selector dùng dấu gạch dưới**: Selector chính xác là `libs_ui-components-buttons-button` (dấu `_` sau `libs`), không phải `libs-ui-components-buttons-button`.

## Unit Tests

```bash
# Chạy test cho lib này
npx nx test components-buttons-button --testFile=libs-ui/components/buttons/button/src/button.component.spec.ts

# Toàn bộ test
npx nx test components-buttons-button
```
