import { domToSvgDataUrl } from './dom-to-image' export interface CodeToElementOptions { title?: string allowScripts?: boolean styles?: string[] } export function codeToElement(code: string, options: CodeToElementOptions = {}): HTMLIFrameElement { const iframe = document.createElement('iframe') const sandbox = new Set() if (!options.allowScripts) { sandbox.add('allow-same-origin') } else { sandbox.add('allow-scripts') } iframe.title = options.title ?? 'Rendered code' iframe.setAttribute('sandbox', Array.from(sandbox).join(' ')) iframe.srcdoc = `${(options.styles ?? []).join('\n')}${code}` return iframe } export async function createCodeThumbnail( code: string, options: CodeToElementOptions = {} ): Promise { const iframe = codeToElement(code, { title: 'Code thumbnail', ...options, allowScripts: false }) iframe.style.width = '640px' iframe.style.height = '360px' iframe.style.position = 'fixed' iframe.style.left = '-10000px' iframe.style.border = '0' document.body.append(iframe) try { await new Promise((resolve, reject) => { iframe.addEventListener('load', () => resolve(), { once: true }) iframe.addEventListener( 'error', () => reject(new Error('Unable to render code thumbnail')), { once: true } ) }) const content = iframe.contentDocument?.body const thumbnail = document.createElement('img') if (content) { thumbnail.src = domToSvgDataUrl(content, { width: 640, height: 360 }) } return thumbnail } finally { iframe.remove() } }