npm package: @libs-ui/components-gallery
Description: > **Version**: 0.2.355-15
Latest version: 0.2.356-23

# Gallery Component

> **Version**: 0.2.355-15

Component hiển thị gallery ảnh với lightbox viewer, hỗ trợ zoom, drag, fullscreen và keyboard navigation.

## Tính năng

- ✅ **Thumbnail Grid**: Hiển thị danh sách ảnh dạng thumbnail
- ✅ **Lightbox Viewer**: Viewer fullscreen với zoom, drag và navigate
- ✅ **String Array Support**: Tự động convert Array<string> sang object format
- ✅ **Overlay Count**: Hiển thị số ảnh còn lại (+N) trên thumbnail cuối
- ✅ **Keyboard Navigation**: Escape (đóng), ArrowLeft/ArrowRight (chuyển ảnh)
- ✅ **Zoom & Drag**: Zoom in/out và drag ảnh trong viewer
- ✅ **Fullscreen**: Chế độ xem fullscreen trong viewer
- ✅ **FunctionsControl**: Điều khiển mở viewer từ bên ngoài
- ✅ **Sub-component Viewer**: Viewer component có thể được export riêng

## Khi nào sử dụng

- Khi cần hiển thị danh sách ảnh dạng thumbnail grid
- Khi cần lightbox viewer với zoom, drag và fullscreen
- Khi cần hiển thị gallery ảnh từ array URLs đơn giản
- Khi cần điều khiển mở viewer từ bên ngoài (FunctionsControl)
- Khi cần hiển thị overlay đếm số ảnh còn lại (+N)

## Important Notes

⚠️ `[images]` là model (two-way binding) — component có thể thay đổi giá trị khi dùng `imageArrayStringConvert`

⚠️ Sử dụng `[imageArrayStringConvert]` khi data là `Array<string>` — component tự convert sang `Array<Record<string, any>>`

⚠️ `[fieldDisplaySrcImage]` xác định key chứa URL ảnh trong object (mặc định `"url"`)

⚠️ Viewer hỗ trợ keyboard: Escape (đóng), ArrowLeft/ArrowRight (chuyển ảnh)

⚠️ Viewer là dynamic component — được inject vào body, không nằm trong DOM tree của gallery

## Installation

```bash
npm install @libs-ui/components-gallery
```

## Usage

### Basic Gallery

```typescript
import { Component } from '@angular/core';
import { LibsUiComponentsGalleryComponent } from '@libs-ui/components-gallery';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [LibsUiComponentsGalleryComponent],
  template: `
    <div class="w-[300px] h-[80px]">
      <libs_ui-components-gallery
        [images]="images"
        [fieldDisplaySrcImage]="'url'"
      />
    </div>
  `,
})
export class ExampleComponent {
  images = [
    { url: 'https://example.com/image1.jpg' },
    { url: 'https://example.com/image2.jpg' },
    { url: 'https://example.com/image3.jpg' },
  ];
}
```

### String Array Convert

```typescript
@Component({
  // ...
  template: `
    <div class="w-[300px] h-[80px]">
      <libs_ui-components-gallery
        [images]="[]"
        [fieldDisplaySrcImage]="'url'"
        [imageArrayStringConvert]="imageUrls"
      />
    </div>
  `,
})
export class ExampleComponent {
  imageUrls = [
    'https://example.com/image1.jpg',
    'https://example.com/image2.jpg',
  ];
}
```

### FunctionsControl

```typescript
import { Component, signal } from '@angular/core';
import { LibsUiComponentsGalleryComponent, IGalleryFunctionsControlEvent } from '@libs-ui/components-gallery';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [LibsUiComponentsGalleryComponent],
  template: `
    <libs_ui-components-gallery
      [images]="images"
      [fieldDisplaySrcImage]="'url'"
      (outFunctionsControl)="controls.set($event)"
    />
    <button (click)="controls()?.open(images[0])">Open Viewer</button>
  `,
})
export class ExampleComponent {
  controls = signal<IGalleryFunctionsControlEvent | null>(null);
  images = [{ url: 'https://example.com/image1.jpg' }];
}
```

## API

### libs_ui-components-gallery

#### Inputs

| Property                     | Type                          | Default     | Description                                             |
| ---------------------------- | ----------------------------- | ----------- | ------------------------------------------------------- |
| `[end]`                      | `number`                      | `3`         | Index kết thúc để hiển thị thumbnails (slice end)        |
| `[fieldDisplaySrcImage]`     | `string`                      | `'url'`     | Key trong object chứa URL ảnh                           |
| `[ignoreOverlayCountImage]`  | `boolean`                     | `false`     | Ẩn overlay đếm số ảnh còn lại (+N)                      |
| `[imageArrayStringConvert]`  | `Array<string>`               | `undefined` | Array URL strings — tự động convert sang images format   |
| `[(images)]`                 | `Array<Record<string, any>>`  | `required`  | Danh sách ảnh (model — two-way binding)                  |
| `[start]`                    | `number`                      | `0`         | Index bắt đầu để hiển thị thumbnails (slice start)       |
| `[zIndex]`                   | `number`                      | `1200`      | z-index của viewer overlay                               |

#### Outputs

| Property                | Type                            | Description                                          |
| ----------------------- | ------------------------------- | ---------------------------------------------------- |
| `(outFunctionsControl)` | `IGalleryFunctionsControlEvent` | Emit functions để điều khiển gallery từ bên ngoài     |
| `(outViewerEvent)`      | `'show' \| 'remove'`           | Event khi viewer được mở hoặc đóng                    |

#### FunctionsControl Methods

| Method               | Description                                              |
| -------------------- | -------------------------------------------------------- |
| `open(imageSelected)`| Mở viewer với ảnh được chọn (`Record<string, any>`)      |
| `viewerRef`          | Tham chiếu đến `ComponentRef` của viewer                 |

### libs_ui-components-gallery-viewer (Sub-component)

Viewer component hiển thị ảnh fullscreen với zoom, drag, fullscreen và navigation.

#### Inputs

| Property                 | Type                          | Default     | Description                          |
| ------------------------ | ----------------------------- | ----------- | ------------------------------------ |
| `[classContainerInclude]`| `string`                      | `undefined` | CSS class thêm vào container          |
| `[fieldDisplaySrcImage]` | `string`                      | `required`  | Key trong object chứa URL ảnh         |
| `[(imageSelected)]`      | `Record<string, any>`         | `undefined` | Ảnh đang được chọn (model)            |
| `[images]`               | `Array<Record<string, any>>`  | `required`  | Danh sách tất cả ảnh                  |
| `[removeBackdrop]`       | `boolean`                     | `false`     | Ẩn backdrop overlay                   |
| `[singleImage]`          | `boolean`                     | `false`     | Chế độ xem 1 ảnh (ẩn thumbnail list)  |
| `[zIndex]`               | `number`                      | `1200`      | z-index của viewer                    |

#### Outputs

| Property     | Type   | Description            |
| ------------ | ------ | ---------------------- |
| `(outClose)` | `void` | Event khi đóng viewer   |

## Types

### IGalleryFunctionsControlEvent

```typescript
export interface IGalleryFunctionsControlEvent {
  open: (imageSelected: Record<string, any>) => Promise<void>;
  viewerRef: ComponentRef<any> | undefined;
}
```

### IZoomDragHTMLElement

```typescript
export interface IZoomDragHTMLElement extends HTMLElement {
  stopDraggableBehavior?(): IZoomDragHTMLElement | null;
}
```

## Hidden Logic

### imageArrayStringConvert → images Conversion

Khi truyền `[imageArrayStringConvert]`, component sử dụng `effect()` để tự động convert `Array<string>` thành `Array<Record<string, any>>` với key là `fieldDisplaySrcImage`. Kết quả được set vào model `images()`.

### Dynamic Viewer Component

Gallery viewer không render inline — nó được lazy-import và inject vào `document.body` thông qua `LibsUiDynamicComponentService`. Điều này đảm bảo viewer luôn hiển thị fullscreen trên tất cả content.

### Overlay Count Logic

Khi số ảnh nhiều hơn `[end]`, thumbnail cuối cùng hiển thị overlay "+N" (N = tổng ảnh - end). Có thể tắt bằng `[ignoreOverlayCountImage]="true"`.

## Demo

- **Local**: [http://localhost:4500/gallery](http://localhost:4500/gallery)

## Test

```bash
nx test components-gallery
```

## License

MIT