# 标签

## 使用方法

`Token` 是可交互的标签（chip），可移除、可点击、可作链接，用于已选值和筛选条件。`Badge` 是静态的状态或计数标记。

自动补全、多选器和标签输入框内部都会用到 `Token`，对话输入区也可以直接拿来表示附件或提及。

`removable` 会显示一个可聚焦的删除按钮。点击、`Backspace` 和 `Delete` 都会发出 `remove`。`disabled` 时删除按钮不再响应。`#icon` 放在文字前面，适合类型图标。

有 `href` 时渲染成链接。删除按钮和链接同时存在时，两者是兄弟节点，按钮不会套在链接里面。

```vue
<script setup lang="ts">
import { Token } from '@astryx-vue/core/Token'
</script>

<template>
  <Token label="设计评审" color="blue" removable>
    <template #icon>
      <span aria-hidden="true">#</span>
    </template>
  </Token>
</template>
```

删除按钮的无障碍名称默认是英文 `Remove 设计评审`。调用 `provideAstryxLocale('zh-CN')` 后改为「移除设计评审」。

### 结构

- **图标**: 标识这个标签类型的前导图标，比如用户头像或分类符号。
- **标签**: 可见文字。labelHidden 为真时，也用作无障碍名称。
- **尾部内容**: 标签后面的内容，比如计数徽章或状态点。
- **移除按钮**: removable 打开时出现的 X 按钮，让用户去掉这个标签。点击会发出 remove。

## 最佳实践

| 指引 | 实践 |
| --- | --- |
| 推荐 | 用户可以拿掉这条信息时打开 `removable`，并在 `remove` 里更新自己的列表。 |
| 推荐 | 用 `#icon` 区分类型，不要把图标写进 `label`。 |
| 避免 | 用标签表达成功、警告这类状态。那种场景用 `Badge`。 |

## 示例

### 可点击

点击后可以当作筛选，或打开详情。

```vue
<script setup lang="ts">
import { Token } from '@astryx-vue/core/Token'
</script>

<template>
  <div class="demo-row">
    <Token label="Bug" color="red" @click="() => {}" />
    <Token label="Feature" color="blue" @click="() => {}" />
    <Token label="Enhancement" color="green" @click="() => {}" />
    <Token label="Documentation" color="gray" @click="() => {}" />
  </div>
</template>

<style scoped>
.demo-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
</style>
```

### 颜色

11 种颜色，各有默认和禁用两种状态。

```vue
<script setup lang="ts">
import type { TokenColor } from '@astryx-vue/core/Token'
import { Token } from '@astryx-vue/core/Token'

const colors: { color: TokenColor, label: string }[] = [
  { color: 'default', label: 'Default' },
  { color: 'red', label: 'Red' },
  { color: 'orange', label: 'Orange' },
  { color: 'yellow', label: 'Yellow' },
  { color: 'green', label: 'Green' },
  { color: 'teal', label: 'Teal' },
  { color: 'cyan', label: 'Cyan' },
  { color: 'blue', label: 'Blue' },
  { color: 'purple', label: 'Purple' },
  { color: 'pink', label: 'Pink' },
  { color: 'gray', label: 'Gray' },
]
</script>

<template>
  <div class="demo-stack">
    <p class="demo-caption">
      {{ 'Default' }}
    </p>
    <div class="demo-row">
      <Token v-for="item in colors" :key="item.color" :label="item.label" :color="item.color" />
    </div>
    <p class="demo-caption">
      {{ 'Disabled' }}
    </p>
    <div class="demo-row">
      <Token v-for="item in colors" :key="`disabled-${item.color}`" :label="item.label" :color="item.color" disabled />
    </div>
  </div>
</template>

<style scoped>
.demo-stack {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-width: 25rem;
}
.demo-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
}
.demo-caption {
  margin: 0.5rem 0 0;
  font-size: 0.875rem;
  color: var(--vp-c-text-2);
}
.demo-caption:first-child {
  margin-top: 0;
}
</style>
```

### 尾部内容

文字后面可以放计数或状态。

```vue
<script setup lang="ts">
import { Badge } from '@astryx-vue/core/Badge'
import { Token } from '@astryx-vue/core/Token'
</script>

<template>
  <div class="demo-row">
    <Token label="Inbox" color="blue">
      <template #end>
        <Badge variant="info">
          12
        </Badge>
      </template>
    </Token>
    <Token label="Reviews" color="purple">
      <template #end>
        <Badge variant="purple">
          3
        </Badge>
      </template>
    </Token>
    <Token label="Resolved" color="green">
      <template #end>
        <Badge variant="success">
          {{ 'Done' }}
        </Badge>
      </template>
    </Token>
  </div>
</template>

<style scoped>
.demo-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
}
</style>
```

### 图标

前面的图标用来区分类型。

```vue
<script setup lang="ts">
import { Token } from '@astryx-vue/core/Token'
</script>

<template>
  <div class="demo-stack">
    <p class="demo-caption">
      {{ 'Icons identify the token category' }}
    </p>
    <div class="demo-row">
      <Token label="Sarah Chen" color="blue">
        <template #icon>
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" /></svg>
        </template>
      </Token>
      <Token label="Featured" color="yellow">
        <template #icon>
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" /></svg>
        </template>
      </Token>
      <Token label="Design" color="purple">
        <template #icon>
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M9.568 3H5.25A2.25 2.25 0 0 0 3 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 0 0 5.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 0 0 9.568 3Z" /><path stroke-linecap="round" stroke-linejoin="round" d="M6 6h.008v.008H6V6Z" /></svg>
        </template>
      </Token>
      <Token label="Verified" color="green">
        <template #icon>
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75m-3-7.036A11.959 11.959 0 0 1 3.598 6 11.99 11.99 0 0 0 3 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285Z" /></svg>
        </template>
      </Token>
    </div>
  </div>
</template>

<style scoped>
.demo-stack {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.demo-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
}
.demo-caption {
  margin: 0;
  font-size: 0.875rem;
  color: var(--vp-c-text-2);
}
.demo-row :deep(svg) {
  width: 0.875rem;
  height: 0.875rem;
}
</style>
```

### 可移除

可以拿掉的筛选条件和收件人。

```vue
<script setup lang="ts">
import { Token } from '@astryx-vue/core/Token'
</script>

<template>
  <div class="demo-container">
    <p class="demo-caption">
      {{ 'Active filters' }}
    </p>
    <div class="demo-row">
      <Token label="Status: Open" color="green" removable />
      <Token label="Priority: High" color="red" removable />
      <Token label="Team: Design" color="purple" removable />
    </div>
    <p class="demo-caption">
      {{ 'Selected recipients' }}
    </p>
    <div class="demo-row">
      <Token label="Sarah Chen" color="blue" removable />
      <Token label="Alex Rivera" color="blue" removable />
      <Token label="Jordan Lee" color="blue" removable />
    </div>
  </div>
</template>

<style scoped>
.demo-container {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.demo-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.demo-caption {
  margin: 0.5rem 0 0;
  font-size: 0.875rem;
  color: var(--vp-c-text-2);
}
.demo-caption:first-child {
  margin-top: 0;
}
</style>
```

## Token Props

| 名称 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `label` | `string` | 必需 | 标签文字，也是无障碍名称。 |
| `color` | `'default' \| 'gray' \| 'blue' \| 'cyan' \| 'teal' \| 'green' \| 'yellow' \| 'orange' \| 'red' \| 'pink' \| 'purple'` | `'default'` | 颜色。 |
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | 尺寸。 |
| `removable` | `boolean` | `false` | 显示可聚焦的删除按钮。 |
| `disabled` | `boolean` | `false` | 禁用。删除按钮不再响应。 |
| `href` | `string` | — | 有值时渲染成链接。和删除按钮同时存在时，链接和按钮是兄弟节点。 |
| `description` | `string` | — | 补充说明，读屏可读。 |
| `isLabelHidden` | `boolean` | `false` | 视觉上隐藏文字，仍然作为无障碍名称。旧名 `labelHidden` 同样可用，两者任一为真就隐藏。 |

## Token Emits

| 名称 | 载荷 | 说明 |
| --- | --- | --- |
| `remove` | `event: Event` | 点击删除按钮，或在标签上按 Backspace / Delete。 |

## Token Slots

| 名称 | 参数 | 说明 |
| --- | --- | --- |
| `icon` | — | 文字前面的图标。 |
| `end` | — | 文字后面、删除按钮前面的内容。也可以写成 `endContent`。 |
