- Accordion
- Alert
- Alert Dialog
- Autocomplete
- Auth Surface
- Avatar
- Badge
- Browse Catalog Dialog
- Button
- Card
- Checkbox
- Checkbox Group
- Collapsible
- Combobox
- Command
- Connector Setup Dialog
- Cookie Banner
- Dialog
- Directory Card
- Directory Detail
- Directory Skeleton
- DrawerНовое
- Token Parts Input
- Empty
- Field
- Fieldset
- File Preview Modal
- File Preview Skeleton
- Form
- Frame
- Group
- Icon
- Input
- Input Group
- Kbd
- Label
- Legal Shell
- Menu
- Mermaid Diagram
- Mind Map Diagram
- Not Found Screen
- Onboarding Frame
- Popover
- PDF Thumbnail
- Personalization Landing
- Preview Card
- Pricing Page
- Progress
- Radio Group
- Ring Spinner
- Scroll Area
- Select
- Separator
- Settings Page
- Settings Skills
- Settings Connectors
- Settings Capabilities
- Settings Usage
- Settings Account
- Settings Billing
- Sheet
- Sidebar
- Skeleton
- Skill Create Dialog
- Slider
- Spinner
- Stat
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Tooltip
- Компоненты AI
- Chat Conversation
- Chat Message
- Chat Response
- Chat Suggestion
- Chat Prompt Input
- Slash Highlighted Textarea
- Chat Search Dialog
- Chat Skill Doc
- Chat Connector Detail
- Chat Attachments
- Chat File Card
- Chat Token Chip
- Chat Code Block
- Chat Image
- Chat Inline Citation
- Chat Sources
- Chat Web Search
- Chat Research
- Chat Source
- Chat Actions
- Chat Context
- Chat Loader
- Chat Compaction
- Chat Timeline
- Chat Snippet
- Chat Terminal
- Chat Stack Trace
- Chat Test Results
- Chat File Tree
- Chat Environment Variables
- Chat Audio Player
- Chat Transcription
- Chat Speech Input
- Chat Mic Selector
- Chat Voice Selector
- Chat Agent
- Chat Persona
- Chat Connection
- Chat Connector Suggestion
- Chat Queue
- Chat Checkpoint
- Chat Confirmation
- Chat Artifact
- Chat JSX Preview
- Chat Schema Display
- Chat Package Info
- Chat Commit
- Chat Plan
- Chat Open In Chat
- Chat Sandbox
- Chat Model Selector
- Chat Canvas
- Chat Node
- Chat Edge
Chat Token Chip
Inline-чип токена /skill и @connector с hover-карточкой.
Я запущу /summarize на спецификации, а затем синхронизирую результаты с @github. У навыка /lint нет описания, поэтому на его карточке отображается только метка типа. Коннектор @deploy отключён: его карточка по-прежнему показывается при наведении, но он недоступен для фокуса и активации.
Наведите курсор или сфокусируйтесь на чипе, чтобы увидеть его карточку — нажмите, чтобы открыть.
"use client";
import { IconBrandGithub } from "@tabler/icons-react";
import { useState } from "react";
import {
ChatMessage,
ChatMessageAvatar,
ChatMessageContent,
} from "@/components/ui/chat-message";
import { ChatTokenChip } from "@/components/ui/chat-token-chip";
const SKILL_DESCRIPTION =
"Сжимает длинные документы в краткую выжимку: выделяет основной тезис, ключевые аргументы и открытые вопросы, а затем оформляет их в виде удобного списка, готового для вставки в отчёт.";
export default function Particle() {
const [opened, setOpened] = useState<string | null>(null);
return (
<div className="flex w-full max-w-2xl flex-col gap-4 p-4">
<ChatMessage from="assistant">
<ChatMessageAvatar fallback="A" />
<ChatMessageContent>
<p className="text-sm leading-relaxed">
Я запущу{" "}
<ChatTokenChip
description={SKILL_DESCRIPTION}
id="summarize"
kind="skill"
label="/summarize"
onOpen={(kind, id) => setOpened(`${kind}:${id}`)}
typeLabel="Навык"
/>{" "}
на спецификации, а затем синхронизирую результаты с{" "}
<ChatTokenChip
description="Подключается к вашему рабочему пространству GitHub, чтобы я мог читать задачи, открывать пул-реквесты и комментировать ревью от вашего имени."
icon={<IconBrandGithub stroke={1.5} />}
id="github"
kind="connector"
label="@github"
onOpen={(kind, id) => setOpened(`${kind}:${id}`)}
typeLabel="Коннектор"
/>
. У навыка{" "}
<ChatTokenChip
id="lint"
kind="skill"
label="/lint"
onOpen={(kind, id) => setOpened(`${kind}:${id}`)}
typeLabel="Навык"
/>{" "}
нет описания, поэтому на его карточке отображается только метка
типа. Коннектор{" "}
<ChatTokenChip
description="Этот коннектор недоступен на вашем текущем тарифе, поэтому его можно посмотреть, но нельзя вызвать."
disabled
id="deploy"
kind="connector"
label="@deploy"
onOpen={(kind, id) => setOpened(`${kind}:${id}`)}
typeLabel="Коннектор"
/>{" "}
отключён: его карточка по-прежнему показывается при наведении, но он
недоступен для фокуса и активации.
</p>
</ChatMessageContent>
</ChatMessage>
<p
aria-live="polite"
className="text-muted-foreground text-xs"
data-slot="preview-status"
>
{opened
? `Открыта карточка: ${opened}`
: "Наведите курсор или сфокусируйтесь на чипе, чтобы увидеть его карточку — нажмите, чтобы открыть."}
</p>
</div>
);
}
Установка
pnpm dlx shadcn@latest add @oracul/chat-token-chip
Использование
import { ChatTokenChip } from "@/components/ui/chat-token-chip";
<p className="text-sm leading-relaxed">
Запущу{" "}
<ChatTokenChip
description="Сжимает длинные документы в краткий бриф с тезисом и ключевыми пунктами."
id="summarize"
kind="skill"
label="/summarize"
onOpen={(kind, id) => console.log(kind, id)}
typeLabel="Навык"
/>{" "}
и синхронизирую результат с{" "}
<ChatTokenChip
description="Подключение к рабочему пространству GitHub."
id="github"
kind="connector"
label="@github"
onOpen={(kind, id) => console.log(kind, id)}
typeLabel="Коннектор"
/>
.
</p>Чип сам по себе — это ссылка-текст (label), а имя в карточке не дублируется.
Карточка повторяет узкую раскладку Claude (w-[178px]): серый бокс с описанием
(line-clamp-5) и под ним тип-лейбл.
Компонент построен на примитиве PreviewCard (богатый hover-контент, привязанный
к inline-ссылке), а не на Tooltip, поэтому всплывающая карточка не объявляется
как role="tooltip". Карточка открывается почти мгновенно (delay={150}).
API намеренно generic: kind — свободная строка (стиль одинаков для всех видов),
typeLabel задаёт вызывающий код (локаль не зашита), icon — произвольная нода.
Состояния
- default — окрашенный чип-токен, карточка скрыта.
kind="skill"иkind="connector"выглядят одинаково. - hover — открывается карточка: при наличии
descriptionпоказывается внутренний muted-бокс с описанием (line-clamp-5), под ним всегда тип-лейбл. - focus-visible — у интерактивного чипа (с
onOpen) при фокусе с клавиатуры появляется кольцоfocus-visible:ring-2 focus-visible:ring-ring, и фокус так же открывает карточку. БезonOpenчип не получает фокус, поэтому фокус не открывает карточку. - active / pressed — при клике или нажатии Enter / Space интерактивный чип
кратко затемняется (
active:opacity-70) и подчёркивается (active:underline). - no-meta fallback —
descriptionотсутствует, бокс описания скрыт, карточка показывает толькоtypeLabel. - с иконкой — опциональный
iconрендерится перед описанием внутри карточки. - clickable — при заданном
onOpenчип получаетrole="button",tabIndex={0},cursor-pointer;onOpen(kind, id)срабатывает по клику и по Enter / Space. БезonOpenчип остаётся не-интерактивным. - disabled —
disabledснимает обработчики и фокус, приглушает лейбл (opacity-50,cursor-not-allowed) и выставляетaria-disabled; карточка по-прежнему открывается по hover, чтобы ссылку можно было осмотреть.
На этой странице