/** * triggerDownload — shared blob → file-download helper. * * Creates a transient object URL for `blob`, clicks a hidden anchor to start * the browser download as `filename`, then revokes the URL. Used by both the * analysis ExportButtons (PDF/CSV) and the Section 6 forecast export control * (.md / .json) — keep it dependency-free so it stays trivially reusable. * * Browser-only: relies on `document` / `URL.createObjectURL`. Call from a * click handler, never during SSR. */ export function triggerDownload(blob: Blob, filename: string): void { const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); // `a.click()` only queues the download — the browser still needs to read the // blob via the object URL after this handler returns. Revoking synchronously // frees the blob too early and intermittently cancels the download in Firefox // and Safari, so defer cleanup to a later tick. setTimeout(() => { document.body.removeChild(a); URL.revokeObjectURL(url); }, 250); }