npm package: @libs-ui/components-buttons-select-color
Description: > Component Button Select Color với color picker tích hợp, hỗ trợ chế độ apply ngay hoặc apply sau.
Latest version: 0.2.356-23

# @libs-ui/components-buttons-select-color

> Component Button Select Color với color picker tích hợp, hỗ trợ chế độ apply ngay hoặc apply sau.

## Giới thiệu

`LibsUiComponentsButtonsSelectColorComponent` là một standalone Angular component được thiết kế để hiển thị button với color picker popover. Component hỗ trợ 2 chế độ: apply ngay (applyNow) khi chọn màu hoặc chọn trước rồi bấm nút Apply.

### Tính năng

- ✅ 2 chế độ: Apply ngay hoặc Apply sau
- ✅ Color picker với đầy đủ định dạng (HEX, RGB, RGBA, HSL, HSLA)
- ✅ Tùy chỉnh button trigger
- ✅ Hỗ trợ external content (custom trigger)
- ✅ Tích hợp popover với nhiều tùy chọn vị trí
- ✅ Emit multiple color formats cùng lúc
- ✅ Tùy chỉnh color picker options
- ✅ Angular Signals cho tính phản hồi cao
- ✅ OnPush Change Detection tối ưu hiệu năng
- ✅ Auto cleanup khi destroy component

## Khi nào sử dụng

- Khi cần cho phép user chọn màu sắc
- Khi cần color picker với nhiều định dạng màu
- Khi cần preview màu trước khi apply (applyNow = false)
- Phù hợp cho theme customization, design tools, color settings

## Cài đặt

```bash
# npm
npm install @libs-ui/components-buttons-select-color

# yarn
yarn add @libs-ui/components-buttons-select-color
```

## Import

```typescript
import { LibsUiComponentsButtonsSelectColorComponent } from '@libs-ui/components-buttons-select-color';
import { IPickerCustomOptions, IOutputColorChangeMultipleType } from '@libs-ui/components-color-picker';
import { IButton } from '@libs-ui/components-buttons-button';

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

## Ví dụ

### Basic - Apply Ngay

```html
<libs_ui-components-buttons-select_color
  [button]="{ label: 'Select Color' }"
  [applyNow]="true"
  (outColorChange)="handleColorChange($event)" />
```

```typescript
handleColorChange(color: string) {
  console.log('Selected color:', color);
}
```

### With Apply Button

```html
<libs_ui-components-buttons-select_color
  [button]="{ label: 'Choose Color' }"
  [applyNow]="false"
  (outColorChange)="handleColorChange($event)"
  (outColorChangeMultipleType)="handleMultipleTypes($event)" />
```

```typescript
handleColorChange(color: string) {
  console.log('Applied color:', color);
}

handleMultipleTypes(colors: IOutputColorChangeMultipleType) {
  console.log('HEX:', colors.hex);
  console.log('RGB:', colors.rgb);
  console.log('RGBA:', colors.rgba);
  console.log('HSL:', colors.hsl);
  console.log('HSLA:', colors.hsla);
  console.log('Alpha:', colors.alpha);
}
```

### Custom Button Style

```html
<libs_ui-components-buttons-select_color
  [button]="{
    label: 'Pick Color',
    type: 'button-secondary',
    classIconLeft: 'libs-ui-icon-color-palette'
  }"
  [applyNow]="true"
  (outColorChange)="handleColorChange($event)" />
```

### Custom Color Picker Options

```html
<libs_ui-components-buttons-select_color
  [button]="{ label: 'Select Color' }"
  [customOptions]="{
    color: '#ff5733',
    showAlpha: true,
    showHex: true,
    showRgb: true,
    showHsl: false,
    format: 'hex'
  }"
  [applyNow]="true"
  (outColorChange)="handleColorChange($event)" />
```

```typescript
customOptions: IPickerCustomOptions = {
  color: '#ff5733',
  showAlpha: true,
  showHex: true,
  showRgb: true,
  showHsl: false,
  format: 'hex',
};
```

### External Content (Custom Trigger)

```html
<libs_ui-components-buttons-select_color
  [externalContent]="true"
  [applyNow]="true"
  (outColorChange)="handleColorChange($event)">
  <div class="libs-ui-buttons-select-color">
    <div
      class="w-10 h-10 rounded border-2 border-gray-300 cursor-pointer"
      [style.background-color]="selectedColor"></div>
  </div>
</libs_ui-components-buttons-select_color>
```

```typescript
selectedColor = '#3b82f6';

handleColorChange(color: string) {
  this.selectedColor = color;
}
```

### Different Popover Directions

```html
<!-- Bottom (default) -->
<libs_ui-components-buttons-select_color
  [button]="{ label: 'Bottom' }"
  [direction]="'bottom'"
  [applyNow]="true" />

<!-- Top -->
<libs_ui-components-buttons-select_color
  [button]="{ label: 'Top' }"
  [direction]="'top'"
  [applyNow]="true" />

<!-- Left -->
<libs_ui-components-buttons-select_color
  [button]="{ label: 'Left' }"
  [direction]="'left'"
  [applyNow]="true" />

<!-- Right -->
<libs_ui-components-buttons-select_color
  [button]="{ label: 'Right' }"
  [direction]="'right'"
  [applyNow]="true" />
```

### Icon Only Button

```html
<libs_ui-components-buttons-select_color
  [button]="{
    classIconLeft: 'libs-ui-icon-color-palette',
    iconOnlyType: true
  }"
  [applyNow]="true"
  (outColorChange)="handleColorChange($event)" />
```

### With Custom Z-Index

```html
<libs_ui-components-buttons-select_color
  [button]="{ label: 'Select Color' }"
  [(zIndex)]="customZIndex"
  [applyNow]="true"
  (outColorChange)="handleColorChange($event)" />
```

```typescript
customZIndex = 2000;
```

## API

### libs_ui-components-buttons-select_color

#### Inputs

| Property            | Type                     | Default     | Description                                       |
| ------------------- | ------------------------ | ----------- | ------------------------------------------------- |
| `[applyNow]`        | `boolean`                | `false`     | Nếu true: chọn xong tự emit; false: cần bấm Apply |
| `[button]`          | `IButton`                | `undefined` | Cấu hình button trigger                           |
| `[customOptions]`   | `IPickerCustomOptions`   | `undefined` | Tùy chỉnh color picker options                    |
| `[direction]`       | `TYPE_POPOVER_DIRECTION` | `'bottom'`  | Hướng hiển thị popover                            |
| `[externalContent]` | `boolean`                | `false`     | Sử dụng custom content thay vì button mặc định    |
| `[(zIndex)]`        | `number`                 | `1200`      | Z-index của popover (two-way binding)             |

#### Outputs

| Property                       | Type                             | Description                                  |
| ------------------------------ | -------------------------------- | -------------------------------------------- |
| `(outColorChange)`             | `string`                         | Emit màu đã chọn (format theo customOptions) |
| `(outColorChangeMultipleType)` | `IOutputColorChangeMultipleType` | Emit tất cả các định dạng màu cùng lúc       |

#### Content Projection

| Selector                           | Description                                       |
| ---------------------------------- | ------------------------------------------------- |
| `div.libs-ui-buttons-select-color` | Custom trigger content (khi externalContent=true) |

## Types & Interfaces

### IButton Interface

```typescript
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;
}
```

### IPickerCustomOptions Interface

```typescript
export interface IPickerCustomOptions {
  /** Kích thước saturation/lightness bar [width, height] */
  slBarSize?: Array<number>;

  /** Kích thước hue bar [width, height] */
  hueBarSize?: Array<number>;

  /** Kích thước alpha bar [width, height] */
  alphaBarSize?: Array<number>;

  /** Hiển thị HSL input */
  showHsl?: boolean;

  /** Hiển thị RGB input */
  showRgb?: boolean;

  /** Hiển thị HEX input */
  showHex?: boolean;

  /** Hiển thị Alpha slider */
  showAlpha?: boolean;

  /** Màu khởi tạo (HEX string hoặc RGB array) */
  color?: string | Array<number>;

  /** Format output mặc định */
  format?: 'rgb' | 'rgba' | 'hsl' | 'hsla' | 'hex' | 'color';
}
```

### IOutputColorChangeMultipleType Interface

```typescript
export interface IOutputColorChangeMultipleType {
  /** Màu dạng RGBA string: "rgba(255, 0, 0, 1)" */
  rgba: string;

  /** Màu dạng RGB string: "rgb(255, 0, 0)" */
  rgb: string;

  /** Màu dạng HEX string: "#ff0000" */
  hex: string;

  /** Màu dạng HSL string: "hsl(0, 100%, 50%)" */
  hsl: string;

  /** Màu dạng HSLA string: "hsla(0, 100%, 50%, 1)" */
  hsla: string;

  /** Giá trị alpha (0-1) */
  alpha: number;
}
```

### TYPE_POPOVER_DIRECTION

```typescript
export type TYPE_POPOVER_DIRECTION = 'top' | 'bottom' | 'left' | 'right';
```

## Behavior

### Apply Now Mode (applyNow = true)

- Khi chọn màu, component tự động emit `outColorChange` và `outColorChangeMultipleType`
- Không hiển thị Cancel/Apply buttons
- Popover vẫn mở sau khi chọn màu (user có thể tiếp tục điều chỉnh)

### Apply Later Mode (applyNow = false)

- Khi chọn màu, component lưu tạm thời màu đã chọn
- Hiển thị Cancel và Apply buttons
- Click Cancel: đóng popover, không emit event
- Click Apply: emit `outColorChange` và `outColorChangeMultipleType`, sau đó đóng popover

### Popover Management

- Component tự động cleanup popover khi destroy (ngOnDestroy)
- Popover có thể được đóng bằng cách click outside (click-toggle mode)
- Z-index có thể được điều chỉnh để tránh conflicts

## Công nghệ

| Technology      | Version | Purpose          |
| --------------- | ------- | ---------------- |
| Angular         | 18+     | Framework        |
| Angular Signals | -       | State management |
| TailwindCSS     | 3.x     | Styling          |
| OnPush          | -       | Change Detection |

## Demo

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

Truy cập: `http://localhost:4500/buttons/select-color`

## Unit Tests

```bash
# Chạy tests
npx nx test buttons-select-color

# Coverage
npx nx test buttons-select-color --coverage

# Watch mode
npx nx test buttons-select-color --watch
```

## Dependencies

- `@angular/core`: >=18.0.0
- `@libs-ui/components-buttons-button`: 0.2.355-14
- `@libs-ui/components-color-picker`: 0.2.355-14
- `@libs-ui/components-popover`: 0.2.355-14
- `@ngx-translate/core`: ^15.0.0

## Important Notes

### ⚠️ External Content Selector

Khi sử dụng `[externalContent]="true"`, content projection PHẢI có class `libs-ui-buttons-select-color`:

```html
<libs_ui-components-buttons-select_color [externalContent]="true">
  <div class="libs-ui-buttons-select-color">
    <!-- Your custom trigger here -->
  </div>
</libs_ui-components-buttons-select_color>
```

### ⚠️ Color Format

- `outColorChange` emit màu theo format được chỉ định trong `customOptions.format`
- Nếu không chỉ định format, mặc định là format của màu input
- `outColorChangeMultipleType` luôn emit tất cả các formats

### ⚠️ Z-Index Management

- Default z-index là 1200
- Nếu có conflicts với modals/dialogs khác, tăng z-index
- Z-index hỗ trợ two-way binding: `[(zIndex)]="myZIndex"`

### ⚠️ Memory Management

Component tự động cleanup popover trong `ngOnDestroy`. Không cần manual cleanup.

## Best Practices

1. **Sử dụng applyNow cho simple use cases**: Nếu không cần preview, dùng `applyNow="true"` để UX tốt hơn
2. **Handle multiple formats**: Sử dụng `outColorChangeMultipleType` khi cần lưu nhiều formats
3. **Custom trigger cho special cases**: Dùng `externalContent` khi cần custom UI (color swatch, preview box...)
4. **Set initial color**: Luôn set `customOptions.color` để có màu khởi tạo
5. **Responsive z-index**: Điều chỉnh z-index phù hợp với layout hierarchy

## Troubleshooting

### Color picker không hiển thị

- Kiểm tra z-index có bị overlap bởi elements khác không
- Verify `@libs-ui/components-color-picker` đã được install
- Check console errors

### External content không hoạt động

- Đảm bảo có class `libs-ui-buttons-select-color` trên wrapper div
- Verify `[externalContent]="true"` được set
- Check content projection syntax

### Màu không đúng format

- Kiểm tra `customOptions.format` setting
- Verify input color format hợp lệ
- Use `outColorChangeMultipleType` để có tất cả formats

### Popover không đóng

- Component tự động cleanup trong ngOnDestroy
- Nếu cần đóng manual, có thể trigger click outside
- Check không có errors trong console

## License

MIT