import { useRef, useState, type ReactElement } from 'react' import { DeleteButton } from './buttons' import { READ_TYPES, type Doc } from './docs' // The paperclip beside the message box. Hovered, it opens a menu: Attach file picks files to add, and // Added files opens the documents added so far, each deleted by two presses on its trash can. A press on the clip itself picks files too. const CLOSE_MS = 250 export function Attach({ docs, onFiles, onDelete, }: { docs: Doc[] onFiles: (files: File[]) => void onDelete: (name: string) => void }): ReactElement { const [open, setOpen] = useState(false) const [added, setAdded] = useState(false) const picker = useRef(null) const timer = useRef | null>(null) const hold = (): void => { if (timer.current) clearTimeout(timer.current) setOpen(true) } const release = (): void => { if (timer.current) clearTimeout(timer.current) timer.current = setTimeout(() => { setOpen(false) setAdded(false) }, CLOSE_MS) } const pick = (): void => { setOpen(false) picker.current?.click() } return (
{open && (
setAdded(true)} onMouseLeave={() => setAdded(false)} > Added files {docs.length} ▸ {added && (
{docs.length === 0 && (
None yet. Drop files on the view, or Attach file.
)} {docs.map((doc) => (
{doc.name} {sizeOf(doc.size)} onDelete(doc.id)} />
))}
)}
)} `.${t}`).join(',')} onChange={(e) => { const files = [...(e.target.files ?? [])] e.target.value = '' onFiles(files) }} />
) } function sizeOf(bytes: number): string { return bytes < 1024 ? `${bytes} B` : bytes < 1024 * 1024 ? `${Math.round(bytes / 1024)} KB` : `${(bytes / 1024 / 1024).toFixed(1)} MB` }