import { toPng, toSvg } from 'html-to-image' import { useMemo, useState } from 'react' import { toast } from 'sonner' import { useStaticEffectEvent } from '@/hooks/useStaticEffectEvent' export const useExportSchemaToImage = () => { const [isDownloading, setIsDownloading] = useState(false) // By doing this once and passing the result to html-to-image options, we avoid html-to-image calculating it for every node. // This improves performance a lot. See https://github.com/bubkoo/html-to-image/issues/542#issuecomment-3249408793 const allPropertyNames = useMemo(() => getAllPropertyNames(), []) const exportSchemaToImage = useStaticEffectEvent( async ({ element, projectRef, x, y, zoom, format, }: { element: HTMLElement projectRef: string x: number y: number zoom: number format: 'svg' | 'png' }) => { setIsDownloading(true) const width = element.clientWidth const height = element.clientHeight const options = { includeStyleProperties: allPropertyNames, backgroundColor: 'white', width, height, style: { width: width.toString(), height: height.toString(), transform: `translate(${x}px, ${y}px) scale(${zoom})`, }, skipFonts: true, } try { if (format === 'svg') { const data = await toSvg(element, options) const a = document.createElement('a') a.setAttribute('download', `briven-schema-${projectRef}.svg`) a.setAttribute('href', data) a.click() toast.success('Successfully downloaded as SVG') } else if (format === 'png') { const data = await toPng(element, options) const a = document.createElement('a') a.setAttribute('download', `briven-schema-${projectRef}.png`) a.setAttribute('href', data) a.click() toast.success('Successfully downloaded as PNG') } } catch (error) { console.error('Failed to download:', error) toast.error(`Failed to download current view: ${(error as Error).message}`) } finally { setIsDownloading(false) } } ) return useMemo( () => ({ isDownloading, exportSchemaToImage }), [isDownloading, exportSchemaToImage] ) } // Get all property names accessible through getComputedStyle(), excluding custom properties export const getAllPropertyNames = () => { if (typeof document === 'undefined' || typeof getComputedStyle === 'undefined') { return [] } const names = [] const style = getComputedStyle(document.documentElement) for (let i = 0; i < style.length; i++) { const name = style[i] if (!name.startsWith('--')) { names.push(name) } } return names }