Attachment
Cards de arquivo e imagem para uploads, com progresso, estados, ações, um gatilho no card inteiro e nomes que mantêm a extensão.
pnpm dlx shadcn@latest add https://hextaui.com/r/attachment.jsonAdiciona o componente, os tokens de tema do HextaUI e quaisquer componentes do HextaUI dos quais ele depende.
Adicione os tokens de tema ao seu CSS global, se ainda não o fez.
Instale as dependências.
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cnCopie e cole o código a seguir no seu projeto.
components/ui/attachment.tsx components/ui/aspect-ratio.tsx components/ui/skeleton.tsx components/ui/button.tsx components/ui/progress.tsx components/ui/scroll-area.tsx lib/motion.ts Atualize os caminhos de importação para corresponder à configuração do seu projeto.
Imagem
variant="image" em <AttachmentMedia /> exibe uma miniatura quadrada com shimmer enquanto carrega. Defina orientation="vertical" para um tile com a prévia no topo.
Estados
state cobre todo o ciclo de vida do envio. Arquivos idle ganham borda tracejada, os títulos de uploading e processing têm shimmer, e os erros deixam a mídia e a descrição em vermelho.
Fluxo de envio
Passe progress enquanto state="uploading" para desenhar uma barra de progresso fina na borda inferior. As prévias de imagem ficam esmaecidas até o envio terminar.
Tamanhos
size escala o padding, a mídia e o texto em conjunto e mantém os cantos internos concêntricos com o card.
Nomes longos
Nomes de arquivo longos são truncados antes da extensão, para que ainda dê para distinguir um .pdf de um .zip. Passe o mouse sobre o nome para lê-lo por inteiro.
Grupo
<AttachmentGroup /> dispõe os anexos em uma linha que rola na horizontal, com bordas que esmaecem e itens que se encaixam no lugar.
Gatilho
<AttachmentTrigger /> torna o card inteiro clicável, por exemplo para abrir uma prévia ou um link, enquanto as ações nele continuam independentes. Dê a ele um aria-label.
Composer
Arquivos adicionados depois do carregamento da página surgem com um pop, e o resto da linha desliza suavemente quando um é removido.
Imagem quebrada
Quando a prévia de uma imagem não carrega, ela recorre a um ícone de arquivo.
Estresse
Nomes hostis em uma coluna estreita, um estado aleatório a cada 60 ms e 200 itens em um grupo. Nada transborda e o layout se mantém.
Da direita para a esquerda
A mídia, o conteúdo e as ações são espelhados, e a barra de progresso preenche a partir da borda inicial.
| Tecla | Ação |
|---|---|
| Tab | Move o foco para cada ação e depois para o gatilho. Ações ocultas em tiles verticais aparecem quando o foco entra no card. |
| EnterSpace | Ativa a ação ou o gatilho em foco. |
- Durante o envio, a barra de progresso tem
role="progressbar"e é rotulada pelo título. - Títulos em string recebem um atributo
titlecom o nome completo, para que nomes truncados ainda possam ser lidos. - As ações só com ícone e o gatilho não têm texto, então sempre dê a eles um
aria-labelcom o nome do arquivo. - Com movimento reduzido ativado, os anexos aparecem sem o efeito pop, a barra de progresso salta em vez de suavizar, e os grupos se reorganizam instantaneamente.
Todas as partes, exceto o grupo, a ação e o gatilho, renderizam um elemento simples e aceitam seus atributos. Os estilos do card são exportados como attachmentVariants.
| Prop | Tipo | Padrão |
|---|---|---|
state | "idle" | "uploading" | "processing" | "error" | "done" | "done" |
progressDe 0 a 100. Exibido apenas durante o envio e limitado a esse intervalo. | number | – |
size | "default" | "sm" | "xs" | "default" |
orientation | "horizontal" | "vertical" | "horizontal" |
| Atributo | Descrição |
|---|---|
data-slot="attachment" | Selecione o card no CSS. |
data-state | O estado atual. |
data-size | O tamanho atual. |
data-orientation | A orientação atual. |
data-slot="attachment-progress" | A barra de progresso, presente durante o envio. |
--attachment-radius | O raio dos cantos do card. Os cantos internos são derivados dele. |
| Prop | Tipo | Padrão |
|---|---|---|
variantimage envolve seu filho em um AspectRatio quadrado com um ícone de arquivo como fallback. | "icon" | "image" | "icon" |
| Atributo | Descrição |
|---|---|
data-slot="attachment-media" | Seleciona a mídia no CSS. |
data-variant | A variante atual. |
Um <div> que contém o título e a descrição e ocupa a largura restante.
| Atributo | Descrição |
|---|---|
data-slot="attachment-content" | Seleciona o conteúdo no CSS. |
| Prop | Tipo | Padrão |
|---|---|---|
childrenUma string é dividida para que sua extensão nunca seja truncada. | ReactNode | – |
titleExibido ao passar o mouse. O padrão é o nome completo. | string | children |
idGerado quando omitido. A barra de progresso é rotulada por ele. | string | – |
| Atributo | Descrição |
|---|---|
data-slot="attachment-title" | Selecione o título no CSS. |
Um <span> de uma linha para o tamanho, o tipo ou o status. Ele é truncado quando falta espaço.
| Atributo | Descrição |
|---|---|
data-slot="attachment-description" | Selecione a descrição no CSS. |
Um <div> para os botões de ação. Em tiles verticais ele flutua sobre a prévia e, em dispositivos com mouse, aparece ao passar o mouse ou ao receber foco.
| Atributo | Descrição |
|---|---|
data-slot="attachment-actions" | Seleciona as ações no CSS. |
Um <Button /> que fica acima do gatilho. Aceita todas as props de Button.
| Prop | Tipo | Padrão |
|---|---|---|
variant | ButtonVariant | "ghost" |
size | ButtonSize | "icon-xs" |
| Atributo | Descrição |
|---|---|
data-slot="attachment-action" | Seleciona as ações no CSS. |
Uma camada invisível que cobre o card inteiro. Combine-a com um gatilho de diálogo, um link ou qualquer botão.
| Prop | Tipo | Padrão |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <button type="button"> |
| Atributo | Descrição |
|---|---|
data-slot="attachment-trigger" | Selecione o gatilho no CSS. |
Um <ScrollArea /> horizontal que se encaixa em cada anexo e anima a linha quando itens são adicionados ou removidos. Aceita todas as props de ScrollArea, exceto scrollbars.
| Atributo | Descrição |
|---|---|
data-slot="attachment-group" | Selecione o grupo no CSS. |
data-slot="attachment-group-list" | A linha que contém os anexos. |
- Aspect ratioUma caixa que mantém sua forma antes de a mídia carregar, exibe um shimmer durante o carregamento, faz a mídia aparecer com fade e usa um fallback quando ela falha.
- ButtonBotões em todas as variantes e tamanhos, com um fluxo integrado de carregamento, sucesso e erro que dispensa o spinner em requisições rápidas.
- MotionAs curvas de easing, as durações e a verificação de movimento reduzido com que todo componente anima, além de hooks para transformações de tamanho e destaques deslizantes.
- ProgressUma barra ou anel que mostra o quanto uma tarefa avançou, suaviza entre as atualizações e desliza enquanto o total é desconhecido.
- Scroll areaRolagem nativa com uma barra de rolagem mínima, bordas que esmaecem apenas onde há mais a ver e um peek opcional que corta o último item ao meio.
- BubbleBalões de mensagem de chat com variantes, cantos agrupados, reações e espaço para conteúdo interativo.
Usado em blocos
Blocos que se baseiam em Attachment.
- Prompt InputUm campo de conversa que começa como uma linha discreta, cresce até virar um card conforme você escreve e desce quando a conversa começa. Enter envia, de forma segura com entrada em japonês e chinês. Cole, solte ou escolha arquivos com prévias, progresso e nova tentativa. @ adiciona arquivos e / executa comandos a partir de um menu no cursor. Um seletor de modelo com teclas numéricas, um slider de esforço que ganha vida no Max, um anel de contexto, ditado com forma de onda ao vivo, chips de ferramentas, uma fila para mensagens digitadas enquanto uma resposta é transmitida e rascunhos que sobrevivem a um recarregamento.
- Chat ThreadA conversa inteira ao redor do composer. Sua pergunta fica fixa no topo enquanto a resposta chega em streaming, checkpoints na lateral saltam entre mensagens, e toda resposta pode ser copiada, editada, repetida, avaliada e alternada entre versões. As respostas renderizam Markdown com blocos de código, tabelas e citações, e o raciocínio, as chamadas de ferramenta e o Prompt Input se encaixam diretamente.