import * as React from "react"; import { Download } from "lucide-react"; import { Button, type ButtonProps } from "@/components/ui/button"; import { defaultCsvFilename, downloadCsv, toCsv, type CsvColumn } from "@/lib/csv"; import { cn } from "@/lib/utils"; export type ExportCsvButtonProps = { /** Rows to serialize. Empty rows → button disabled with a tooltip. */ rows: T[]; /** Column descriptors (header + per-row extractor). */ columns: CsvColumn[]; /** Override the download filename. Defaults to `{prefix}-{YYYY-MM-DD}.csv`. */ filename?: string; /** Filename prefix when no explicit filename is provided. */ filenamePrefix?: string; /** Visible label. Defaults to "Export CSV". */ label?: string; /** Render an icon-only button with `aria-label="Export as CSV"`. */ iconOnly?: boolean; /** Forwarded to the underlying Button. */ disabled?: boolean; /** Forwarded to the underlying Button for layout tweaks. */ className?: string; } & Omit; /** * One-line CSV export: a page passes `rows` + `columns`, we serialize and * trigger a download. Disabled (with a tooltip) when there's nothing to * export. The "Exporting..." state is decorative — `downloadCsv` is sync — * but it gives the click tactile feedback so the action feels deliberate. */ export function ExportCsvButton({ rows, columns, filename, filenamePrefix = "export", label = "Export CSV", iconOnly = false, disabled, className, variant = "outline", size, type = "button", ...buttonProps }: ExportCsvButtonProps) { const [busy, setBusy] = React.useState(false); const nothingToExport = rows.length === 0; const isDisabled = disabled || nothingToExport; const handleClick = React.useCallback(() => { if (isDisabled) return; const csv = toCsv(rows, columns); const finalName = filename ?? defaultCsvFilename(filenamePrefix); setBusy(true); try { downloadCsv(finalName, csv); } finally { // Reset on the next tick so the user sees the busy state flash. queueMicrotask(() => setBusy(false)); } }, [columns, filename, filenamePrefix, isDisabled, rows]); const tooltip = nothingToExport ? "No rows to export" : undefined; return ( ); }