import { CircularProgress, IconButton, ListItemIcon, ListItemText, Menu, MenuItem, } from '@mui/material' import type { DownloadItem, DownloadProps } from './types' import { FileDownloadOutlined } from '@mui/icons-material' import { useState, type MouseEvent } from 'react' import { useWidgetSelector } from '../../stores/use-widget-selector' const EMPTY_LABELS: NonNullable = {} /** * Dropdown menu action for exporting widget data in various formats (CSV, PNG, etc.). * * Reads widget data from the store and triggers downloads using the modifier * function defined in each `DownloadItem`. * * @example * ```tsx * * ``` */ export function Download({ id, items, labels = EMPTY_LABELS, Icon, IconButtonProps, }: DownloadProps) { const { data } = useWidgetSelector(id, (w) => ({ data: w?.data, })) const [isDownloading, setIsDownloading] = useState(false) const [anchorEl, setAnchorEl] = useState(null) const handleToggle = (event: MouseEvent) => { event.stopPropagation() setAnchorEl(event.currentTarget) } const handleDownload = (data: string, option: DownloadItem) => { const link = document.createElement('a') link.href = data link.download = option.filename ?? id link.style.display = 'none' document.body.appendChild(link) link.click() document.body.removeChild(link) option.callback?.(link.href) } const handleClick = async ( event: MouseEvent, option: DownloadItem, ) => { event.stopPropagation() setIsDownloading(true) setAnchorEl(null) const result = await option.modifier(data) if (!result) { setIsDownloading(false) return } handleDownload(result, option) setIsDownloading(false) } return ( <> {isDownloading ? ( ) : ( (Icon ?? ) )} setAnchorEl(null)} MenuListProps={{ sx: { paddingBottom: 0, }, }} > {items.map((option) => ( void handleClick(e, option)} > {option.icon && ( {option.icon} )} {option.label} ))} ) }