# HoverCard

Card xem trước mở khi hover hoặc focus bàn phím trên một link (một người dùng, một repository, một mục) và hiện thêm về đích. Người dùng chuột nhìn thấy màn hình nhận được bản xem trước; link vẫn hoạt động khi đứng một mình. Dùng Tooltip cho nhãn ngắn, Popover cho nội dung mở bằng click và chứa control.

**Phụ thuộc:** npm: 0 trực tiếp, 2 tổng; registry: 3 trực tiếp, 3 tổng.

## Cách dùng

### Khi nào dùng

- Hiện chi tiết chỉ đọc về một người hoặc một mục được link khi người dùng chuột hover hoặc người dùng bàn phím focus vào đó.
- Giữ link hữu ích trên cảm ứng, nơi một lần chạm đi tới đích mà không mở bản xem trước.

### Khi nào không dùng

- Nhãn ngắn cho một control. Dùng Tooltip.
- Một panel có button, field hoặc control khác. Dùng Popover.

## Biến thể

### side

Trên HoverCardContent: cạnh ưu tiên; lật khi không đủ chỗ.

Giá trị: `top`, `right`, `bottom`, `left`. Mặc định: `bottom`.

### align

Trên HoverCardContent: căn dọc theo trigger.

Giá trị: `start`, `center`, `end`. Mặc định: `center`.

## Ví dụ

### Xem trước người dùng

```tsx
<HoverCard>
  <HoverCardTrigger asChild>
    <Link href="#khanh">Khanh Nguyen</Link>
  </HoverCardTrigger>
  <HoverCardContent>
    <div className="flex items-start gap-md">
      <Avatar alt="" size="lg">KN</Avatar>
      <div className="flex flex-col gap-xs">
        <p className="text-sm font-medium">Khanh Nguyen</p>
        <p className="text-sm text-text-secondary">Nhà thiết kế sản phẩm</p>
      </div>
    </div>
  </HoverCardContent>
</HoverCard>
```

### Xem trước dự án

```tsx
<HoverCard>
  <HoverCardTrigger asChild>
    <Link href="#workspace">Không gian làm việc</Link>
  </HoverCardTrigger>
  <HoverCardContent side="right" align="start">
    <p className="text-sm font-medium">Không gian làm việc</p>
    <p className="text-sm text-text-secondary">Tệp được chia sẻ và ghi chú dự án cho nhóm của bạn.</p>
    <Badge>Riêng tư</Badge>
  </HoverCardContent>
</HoverCard>
```

### Độ trễ ngắn

Card mở sau 200ms và đóng sau 100ms. Một lần chạm trên cảm ứng vẫn đi theo link.

```tsx
<HoverCard openDelay={200} closeDelay={100}>
  <HoverCardTrigger asChild>
    <Link href="#report">Báo cáo quý</Link>
  </HoverCardTrigger>
  <HoverCardContent side="top" align="end" sideOffset={8}>
    <p className="text-sm font-medium">Báo cáo quý</p>
    <p className="text-sm text-text-secondary">Xem xét các cập nhật dự án mới nhất trước khi mở tài liệu.</p>
  </HoverCardContent>
</HoverCard>
```

## Nên và không nên

### Nên

- Giữ nội dung chỉ đọc.
- Nở từ phía trigger (origin theo cạnh), thoát bằng animate-exit-scale.

### Không nên

- Đừng đặt button hoặc form bên trong; dùng Popover.
- Đừng dùng trên button; chỉ dùng cho link.

## Props

| Tên | Kiểu | Giá trị | Mặc định | Mô tả |
| --- | --- | --- | --- | --- |
| `open` | `boolean` |  |  | Trạng thái mở khi controlled. |
| `defaultOpen` | `boolean` |  | `false` | Trạng thái mở ban đầu. |
| `onOpenChange` | `(open: boolean) => void` |  |  | Được gọi khi mở hoặc đóng. |
| `openDelay` | `number` |  | `600` | Số mili giây trước khi mở. |
| `closeDelay` | `number` |  | `300` | Số mili giây trước khi đóng. |
| `side` | `enum` | `top`, `right`, `bottom`, `left` | `bottom` | Trên HoverCardContent: cạnh ưu tiên; lật khi không đủ chỗ. |
| `align` | `enum` | `start`, `center`, `end` | `center` | Trên HoverCardContent: căn dọc theo trigger. |
| `sideOffset` | `number` |  | `4` | Trên HoverCardContent: khoảng cách từ trigger, tính bằng px. |
| `asChild` | `boolean` |  | `false` | Trên HoverCardTrigger: gắn hành vi hover và focus lên một phần tử con là link thật. Dùng true cho Link hoặc a. |
| `alignOffset` | `number` |  | `0` | Trên HoverCardContent: độ lệch dọc theo trục căn, tính bằng px. |
| `avoidCollisions` | `boolean` |  | `true` | Trên HoverCardContent: dịch hoặc lật bản xem trước để giữ trong viewport. |
| `collisionPadding` | `number \| Partial<Record<"top" \| "right" \| "bottom" \| "left", number>>` |  | `8` | Trên HoverCardContent: khoảng cách tối thiểu tới mép viewport, tính bằng px. |

### Slot

| Tên | Bắt buộc | Mô tả |
| --- | --- | --- |
| `trigger` | có | Link mở card. |
| `content` | có | Nội dung xem trước: Avatar, tên, văn bản ngắn, Metadata. |

## Cấu tạo

| Phần | Mô tả |
| --- | --- |
| `root` | HoverCard: giữ trạng thái mở, không render gì. |
| `trigger` | HoverCardTrigger: một link, thường là Link với asChild. |
| `content` | HoverCardContent: card nổi chỉ đọc, rộng 320px theo mặc định, trên lớp xếp chồng popover. |

## Khả năng truy cập

Role: `none`

| Phím | Hành động |
| --- | --- |
| `Tab` | Focus trên trigger mở card sau openDelay; rời focus thì đóng sau closeDelay. |
| `Escape` | Đóng card; focus giữ trên trigger. |

- Nội dung mang tính bổ sung: không nằm trong thứ tự tab và không được là đường dẫn duy nhất tới một hành động.
- Trigger là một link thật; card không đổi tên của link. Đặt thông tin thiết yếu trong văn bản của link.
- Trên cảm ứng không có hover: một lần chạm đi theo link và card không mở.
- Card giữ mở khi con trỏ di từ trigger vào trong card.

## Cài đặt

```bash
npx werewolf-ui add hover-card
```

Chạy `npx werewolf-ui init` một lần trong app trước khi thêm component. Init cài token, thêm CSS import và luật cho agent. Add cài component này cùng các dependency và giữ nguyên theme của bạn. Xem [Cài đặt](https://www.werewolf-ui.dev/vi/docs/installation.md) để biết yêu cầu và cách cài qua registry.
