Attachment

A file or image going with a message, with upload progress, remove and retry.

tasting-notes.pdfUploading 0%
roast-log.csv18 KB
farm-visit.movToo large to upload
'use client';

import { useEffect, useState } from 'react';
import { Attachment } from '@brand-studio/ui';

export default function AttachmentDemo() {
  const [progress, setProgress] = useState(0);
  const [failed, setFailed] = useState(true);
  const [files, setFiles] = useState(['tasting-notes.pdf', 'roast-log.csv']);
  useEffect(() => {
    if (progress >= 100) return;
    const timer = setTimeout(() => setProgress(value => Math.min(100, value + 7)), 180);
    return () => clearTimeout(timer);
  }, [progress]);
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10, justifyContent: 'center' }}>
      {files.includes('tasting-notes.pdf') && <Attachment name="tasting-notes.pdf" size="240 KB" progress={progress} onRemove={() => setFiles(list => list.filter(file => file !== 'tasting-notes.pdf'))} />}
      {files.includes('roast-log.csv') && <Attachment name="roast-log.csv" size="18 KB" onRemove={() => setFiles(list => list.filter(file => file !== 'roast-log.csv'))} />}
      <Attachment name="farm-visit.mov" size="1.2 GB" error={failed ? 'Too large to upload' : undefined} progress={failed ? undefined : 30} onRetry={() => setFailed(false)} />
    </div>
  );
}

Installation

pnpm add @brand-studio/ui

Usage

import { Attachment } from '@brand-studio/ui';
<Attachment name="tasting-notes.pdf" size="240 KB" progress={progress} onRemove={remove} />
<Attachment name="farm-visit.mov" error="Too large to upload" onRetry={retry} onRemove={remove} />

Pass progress from 0 to 100 while the file uploads; at 100 or unset, the size shows. preview takes an image URL for a thumbnail; otherwise the file type shows. An error replaces the size and, with onRetry, adds a retry button.

Accessibility

  • Remove and retry name the file: "Remove tasting-notes.pdf".
  • Upload progress is a labelled progress bar, and an error is announced when it appears.

API Reference

PropTypeDefault
namestring
size?string
preview?string
progress?number
error?string
onRemove?(() => void)
onRetry?(() => void)
className?string''

Still, Deskhand and Hollis are fictional brands. The coffee photographs are original generated artwork. @brand-studio/ui is MIT licensed.