# @libs-ui/components-card

> Component card với header có thể collapse/expand, hỗ trợ custom template và nhiều tùy chỉnh styling.

## Giới thiệu

`LibsUiComponentsCardComponent` là một standalone Angular component để hiển thị nội dung trong một container có header và body, với khả năng collapse/expand nội dung.

**Version**: 0.2.355-14

### Tính năng

- ✅ Header có thể collapse/expand
- ✅ Custom template cho header
- ✅ Two-way binding cho trạng thái ẩn/hiện
- ✅ Điều khiển từ component cha thông qua FunctionsControl
- ✅ Nhiều tùy chỉnh styling (border, background, icon position...)
- ✅ OnPush Change Detection
- ✅ Angular Signals

## Khi nào sử dụng

- Hiển thị nội dung trong một container có header và body
- Cần collapse/expand nội dung để tiết kiệm không gian
- Tạo các section có thể đóng/mở trong form hoặc dashboard
- Nhóm các thông tin liên quan với nhau

## ⚠️ Important Notes

- **clickExactly**: Khi true, chỉ click vào icon collapse mới toggle. Khi false, click vào toàn bộ header sẽ toggle.
- **templateHeader**: Khi sử dụng custom template header, label input sẽ bị ignore.
- **FunctionsControl**: Emit qua outFunctionsControl trong ngOnInit, cần lưu reference để điều khiển từ component cha.

## Cài đặt

```bash
# npm
npm install @libs-ui/components-card

# yarn
yarn add @libs-ui/components-card
```

## Import

```typescript
import { LibsUiComponentsCardComponent, IConfigCard, IFunctionControlCard } from '@libs-ui/components-card';

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

## Ví dụ

### Basic Usage

```html
<libs_ui-components-card [label]="{ labelLeft: 'Card Title' }">
  <p>Card content goes here</p>
</libs_ui-components-card>
```

### Collapsible Card

```html
<libs_ui-components-card
  [label]="{ labelLeft: 'Collapsible Card', required: true }"
  [hasCollapseBtn]="true"
  [(isHidden)]="isCardHidden"
  (outChangeStateShowContent)="onStateChange($event)">
  <div class="p-4">
    <p>This content can be collapsed/expanded</p>
  </div>
</libs_ui-components-card>
```

```typescript
export class ExampleComponent {
  isCardHidden = signal<boolean>(false);

  onStateChange(isHidden: boolean) {
    console.log('Card is now:', isHidden ? 'hidden' : 'visible');
  }
}
```

### Custom Configuration

```html
<libs_ui-components-card
  [label]="{ labelLeft: 'Custom Styled Card' }"
  [hasCollapseBtn]="true"
  [configCard]="{
    ignoreBorderHeader: false,
    ignoreBackgroundHeader: false,
    iconConRight: true,
    classIncludeLabel: 'text-lg font-bold text-blue-600'
  }"
  [classIncludeBody]="'bg-gray-50 p-6'">
  <div>
    <h3>Custom Configuration</h3>
    <p>Icon on the right, custom label styling, custom body background</p>
  </div>
</libs_ui-components-card>
```

### External Control

```html
<button (click)="cardControls?.changeHidden()">Toggle Card Content</button>

<libs_ui-components-card
  [label]="{ labelLeft: 'Externally Controlled Card' }"
  [hasCollapseBtn]="true"
  (outFunctionsControl)="cardControls = $event"
  (outChangeStateShowContent)="isCardHidden = $event">
  <div class="p-4">
    <p>This card can be controlled from external buttons</p>
  </div>
</libs_ui-components-card>
```

```typescript
export class ExampleComponent {
  cardControls: IFunctionControlCard | null = null;
  isCardHidden = false;
}
```

## API

### libs_ui-components-card

#### Inputs

| Property                                | Type              | Default     | Description                                                  |
| --------------------------------------- | ----------------- | ----------- | ------------------------------------------------------------ |
| `[classIncludeBody]`                    | `string`          | `-`         | Class CSS thêm vào body                                      |
| `[classIncludeHeader]`                  | `string`          | `-`         | Class CSS thêm vào header                                    |
| `[classIncludeHeaderWhenHiddenContent]` | `string`          | `-`         | Class CSS thêm vào header khi content bị ẩn                  |
| `[clickExactly]`                        | `boolean`         | `false`     | True: chỉ click icon mới toggle. False: click toàn bộ header |
| `[configCard]`                          | `IConfigCard`     | `undefined` | Cấu hình styling và behavior của card                        |
| `[hasCollapseBtn]`                      | `boolean`         | `false`     | Hiển thị nút collapse/expand                                 |
| `[ignoreTitle]`                         | `boolean`         | `false`     | Ẩn header, chỉ hiển thị body                                 |
| `[isHidden]`                            | `boolean (model)` | `false`     | Trạng thái ẩn/hiện content (two-way binding)                 |
| `[label]`                               | `ILabel`          | `undefined` | Label hiển thị trong header                                  |
| `[templateHeader]`                      | `TemplateRef`     | `undefined` | Custom template cho header (override label)                  |

#### Outputs

| Property                      | Type                   | Description                                        |
| ----------------------------- | ---------------------- | -------------------------------------------------- |
| `(outChangeStateShowContent)` | `boolean`              | Emit khi trạng thái ẩn/hiện thay đổi               |
| `(outFunctionsControl)`       | `IFunctionControlCard` | Emit functions để điều khiển card từ component cha |

#### IFunctionControlCard Methods

| Method           | Description                       |
| ---------------- | --------------------------------- |
| `changeHidden()` | Toggle trạng thái ẩn/hiện content |

## Types & Interfaces

```typescript
interface IConfigCard {
  ignorePaddingLeft?: boolean;
  ignoreBorderHeader?: boolean;
  ignoreBackgroundHeader?: boolean;
  iconConRight?: boolean;
  width?: string;
  classIncludeLabel?: string;
  classIconInclude?: string;
  classIconWhenShowContent?: string;
  classIconWhenHiddenContent?: string;
  ignoreBorderRadiusHeader?: boolean;
  ignoreBorderBody?: boolean;
}

interface IFunctionControlCard {
  changeHidden: () => Promise<void>;
}

interface ILabel {
  labelLeft?: string;
  required?: boolean;
  popover?: string;
}
```

### IConfigCard

Cấu hình styling và behavior của card component.

### IFunctionControlCard

Interface chứa methods để điều khiển card từ component cha.

### ILabel

Cấu hình label hiển thị trong header.

## Công nghệ

| Technology      | Version | Purpose          |
| --------------- | ------- | ---------------- |
| Angular         | 18+     | Framework        |
| Angular Signals | -       | State management |
| OnPush          | -       | Change Detection |

## Demo

**Local**: [http://localhost:4500/card](http://localhost:4500/card)

```bash
npx nx serve core-ui
```

Truy cập: `http://localhost:4500/card`

## Unit Tests

```bash
# Chạy tests
npx nx test components-card

# Coverage
npx nx test components-card --coverage

# Watch mode
npx nx test components-card --watch
```

## License

MIT
