AttachmentSquare
Квадратный тайл прикреплённого файла. По умолчанию показывает превью или иконку; при hover (или фокусе на actions) поверх появляется overlay с заголовком/описанием и actions.
Когда использовать
- В галереях превью и сетках, где у файлов есть визуальный смысл.
- Когда важна плотность —
s(80×80) иm(100×100).
Анатомия
Size (default s)
s— 80×80.m— 100×100.
Hover-overlay
При hover и при фокусе на любой action-кнопке (download/delete/retry) над основным контентом появляется overlay с заголовком/описанием и actions. В image-mode overlay плотный (solid neutral/background1Level) и перекрывает превью; в icon-mode — прозрачный, текст MainContent проступает сквозь, а Actions подменяют слот иконки. Состояние «фокус удерживает overlay» реализовано через внутренний контекст AttachmentFocusActionsContext.
State
loading— спиннер вместо превью, actions скрыты, hover-overlay отключён.disabled— карточка не реагирует на клик, opacity снижается доeffect/opacity/disabled.error— фон тайла переключается наred/background, actionretryзаменяетdownload; в error-режиме overlay прозрачный, чтобы красная заливка пропускалась.checked— accent-border + собственныйcheckedOverlayповерх MainContent с токенамиactivated/default/filled→activated/hovered/filled(Card-овский state-layer закрыт full-bleed image, поэтому overlay рендерится отдельным слоем). Check-badge в верхнем левом углу.
Установка
pnpm add @cloud-ru/ds-attachment
import { AttachmentSquare } from '@cloud-ru/ds-attachment'
Примеры использования
Базовый
invoice-2026
PDF
tsx
import { AttachmentSquare } from '@cloud-ru/ds-attachment';
import { PDF_FILE } from './sample';
export function AttachmentSquareBasic() {
return (
<AttachmentSquare
file={PDF_FILE}
onDownload={file => console.info('download', file?.name)}
onDelete={file => console.info('delete', file?.name)}
/>
);
}С изображением (size m)
tsx
import { AttachmentSquare } from '@cloud-ru/ds-attachment';
import { useEffect, useState } from 'react';
import pictureUrl from './picture.jpg?url';
export function AttachmentSquareImage() {
const [file, setFile] = useState<File>();
useEffect(() => {
fetch(pictureUrl)
.then(r => r.blob())
.then(blob => setFile(new File([blob], 'picture.jpg', { type: 'image/jpg' })));
}, []);
return (
<AttachmentSquare
size='m'
file={file}
onDownload={f => console.info('download', f?.name)}
onDelete={f => console.info('delete', f?.name)}
/>
);
}Props
Types
Props
AttachmentSquareProps| Prop | Type | Default | Required | Description |
|---|---|---|---|---|
checked | boolean | — | no | Состояние «выбран» (множественный выбор) |
className | string | — | no | CSS-класс корня |
data-test-id | string | — | no | |
description | string | fileExtension | no | Описание |
disabled | boolean | — | no | Заблокировано |
error | string | — | no | Сообщение об ошибке |
file | File | — | no | Файл |
icon | JSXElementConstructor<{ size?: number; className?: string; }> | undefined | — | no | Иконка для файла @defaultIcon FileSVG |
loading | boolean | — | no | Управление состоянием загрузки |
onClick | ((event: MouseEvent<HTMLDivElement, MouseEvent>) => void) | — | no | Клик по карточке |
onDelete | ((file?: File) => void) | — | no | Колбек на клик по кнопке удаления |
onDownload | ((file?: File) => void) | — | no | Колбек на клик по кнопке скачивани я |
onRetry | (() => void) | — | no | Колбек на клик по кнопке повторения |
size | "m" | "s" | s | no | Размер |
title | string | fileName | no | Заголовок |
truncateVariant | "end" | "middle" | — | no | Вариант обрезания строки: <br> - `end` — с конца; <br> - `middle` — по середине |