beta/src/components/MDX/Sandpack/DownloadButton.tsx (78 lines of code) (raw):

/* * Copyright (c) Facebook, Inc. and its affiliates. */ import * as React from 'react'; import {useSandpack} from '@codesandbox/sandpack-react'; import {IconArrowSmall} from '../../Icon/IconArrowSmall'; export interface DownloadButtonProps {} let initialIsSupported = false; export const DownloadButton: React.FC<DownloadButtonProps> = () => { const {sandpack} = useSandpack(); const [supported, setSupported] = React.useState(initialIsSupported); React.useEffect(() => { // This detection will work in Chrome 97+ if ( !supported && (HTMLScriptElement as any).supports && (HTMLScriptElement as any).supports('importmap') ) { setSupported(true); initialIsSupported = true; } }, [supported]); if (!supported) { return null; } const downloadHTML = () => { const css = sandpack.files['/styles.css']?.code ?? ''; const code = sandpack.files['/App.js']?.code ?? ''; const blob = new Blob([ `<!DOCTYPE html> <html> <body> <div id="root"></div> </body> <!-- This setup is not suitable for production. --> <!-- Only use it in development! --> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <script type="importmap"> { "imports": { "react": "https://cdn.skypack.dev/react", "react-dom": "https://cdn.skypack.dev/react-dom" } } </script> <script type="text/babel" data-type="module"> import * as React from 'react'; import * as ReactDOM from 'react-dom'; ${code.replace('export default ', 'let Root = ')} ReactDOM.render( <Root />, document.getElementById('root') ); </script> <style> ${css} </style> </html>`, ]); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.style.display = 'none'; a.href = url; a.download = 'sandbox.html'; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); }; return ( <button className="text-sm text-primary dark:text-primary-dark inline-flex items-center hover:text-link duration-100 ease-in transition mx-1" onClick={downloadHTML} title="Download Sandbox" type="button"> <IconArrowSmall displayDirection="down" className="inline mb-0.5 mr-1 mt-1" />{' '} Download </button> ); };