export type ExcelValue = string | number | boolean | Date | null | undefined; export type ExcelExportOptions = { fileName: string; sheetName: string; headers: string[]; rows: ExcelValue[][]; }; function safeFileName(value: string): string { return value.replace(/[\\/:*?"<>|]/g, "_").replace(/\.xlsx$/i, ""); } function safeSheetName(value: string): string { return value.replace(/[\\/*?:\[\]]/g, "_").slice(0, 31) || "Sheet1"; } export async function exportRowsToExcel({ fileName, sheetName, headers, rows }: ExcelExportOptions): Promise { const { default: writeExcelFile } = await import("write-excel-file/browser"); const headerRow = headers.map((value) => ({ value, fontWeight: "bold" as const, backgroundColor: "#EDF6FF", align: "center" as const, })); const columns = headers.map((header, index) => { const maxLength = Math.max(header.length * 2, ...rows.map((row) => String(row[index] ?? "").length)); return { width: Math.min(42, Math.max(12, maxLength + 3)) }; }); await writeExcelFile([headerRow, ...rows], { sheet: safeSheetName(sheetName), stickyRowsCount: 1, columns, }).toFile(`${safeFileName(fileName)}.xlsx`); }