(() => { function convertModuleLinks(html) { html = html .replace(/@shoelace-style\/shoelace/g, `https://esm.sh/@shoelace-style/shoelace@${shoelaceVersion}`) .replace(/from 'react'/g, `from 'https://esm.sh/react@${reactVersion}'`) .replace(/from "react"/g, `from "https://esm.sh/react@${reactVersion}"`); return html; } function getAdjacentExample(name, pre) { let currentPre = pre.nextElementSibling; while (currentPre?.tagName.toLowerCase() === 'pre') { if (currentPre?.getAttribute('data-lang').split(' ').includes(name)) { return currentPre; } currentPre = currentPre.nextElementSibling; } return null; } function runScript(script) { const newScript = document.createElement('script'); if (script.type === 'module') { newScript.type = 'module'; newScript.textContent = script.innerHTML; } else { newScript.appendChild(document.createTextNode(`(() => { ${script.innerHTML} })();`)); } script.parentNode.replaceChild(newScript, script); } function getFlavor() { return sessionStorage.getItem('flavor') || 'html'; } function setFlavor(newFlavor) { flavor = ['html', 'react'].includes(newFlavor) ? newFlavor : 'html'; sessionStorage.setItem('flavor', flavor); // Set the flavor class on the body document.documentElement.classList.toggle('flavor-html', flavor === 'html'); document.documentElement.classList.toggle('flavor-react', flavor === 'react'); } function syncFlavor() { setFlavor(getFlavor()); document.querySelectorAll('.code-preview__button--html').forEach(preview => { if (flavor === 'html') { preview.classList.add('code-preview__button--selected'); } }); document.querySelectorAll('.code-preview__button--react').forEach(preview => { if (flavor === 'react') { preview.classList.add('code-preview__button--selected'); } }); } const shoelaceVersion = document.documentElement.getAttribute('data-shoelace-version'); const reactVersion = '18.2.0'; const cdndir = 'cdn'; const npmdir = 'dist'; let flavor = getFlavor(); let count = 1; // We need the version to open if (!shoelaceVersion) { throw new Error('The data-shoelace-version attribute is missing from .'); } // Sync flavor UI on page load syncFlavor(); // // Resizing previews // document.addEventListener('mousedown', handleResizerDrag); document.addEventListener('touchstart', handleResizerDrag, { passive: true }); function handleResizerDrag(event) { const resizer = event.target.closest('.code-preview__resizer'); const preview = event.target.closest('.code-preview__preview'); if (!resizer || !preview) return; let startX = event.changedTouches ? event.changedTouches[0].pageX : event.clientX; let startWidth = parseInt(document.defaultView.getComputedStyle(preview).width, 10); event.preventDefault(); preview.classList.add('code-preview__preview--dragging'); document.documentElement.addEventListener('mousemove', dragMove); document.documentElement.addEventListener('touchmove', dragMove); document.documentElement.addEventListener('mouseup', dragStop); document.documentElement.addEventListener('touchend', dragStop); function dragMove(event) { const width = startWidth + (event.changedTouches ? event.changedTouches[0].pageX : event.pageX) - startX; preview.style.width = `${width}px`; } function dragStop() { preview.classList.remove('code-preview__preview--dragging'); document.documentElement.removeEventListener('mousemove', dragMove); document.documentElement.removeEventListener('touchmove', dragMove); document.documentElement.removeEventListener('mouseup', dragStop); document.documentElement.removeEventListener('touchend', dragStop); } } // // Toggle source mode // document.addEventListener('click', event => { const button = event.target.closest('.code-preview__button'); const codeBlock = button?.closest('.code-preview'); if (button?.classList.contains('code-preview__button--html')) { // Show HTML setFlavor('html'); toggleSource(codeBlock, true); } else if (button?.classList.contains('code-preview__button--react')) { // Show React setFlavor('react'); toggleSource(codeBlock, true); } else if (button?.classList.contains('code-preview__toggle')) { // Toggle source toggleSource(codeBlock); } else { return; } // Update flavor buttons [...document.querySelectorAll('.code-preview')].forEach(cb => { cb.querySelector('.code-preview__button--html')?.classList.toggle( 'code-preview__button--selected', flavor === 'html' ); cb.querySelector('.code-preview__button--react')?.classList.toggle( 'code-preview__button--selected', flavor === 'react' ); }); }); function toggleSource(codeBlock, force) { codeBlock.classList.toggle('code-preview--expanded', force); event.target.setAttribute('aria-expanded', codeBlock.classList.contains('code-preview--expanded')); } // // Open in CodePen // document.addEventListener('click', event => { const button = event.target.closest('button'); if (button?.classList.contains('code-preview__button--codepen')) { const codeBlock = button.closest('.code-preview'); const htmlExample = codeBlock.querySelector('.code-preview__source--html > pre > code')?.textContent; const reactExample = codeBlock.querySelector('.code-preview__source--react > pre > code')?.textContent; const isReact = flavor === 'react' && typeof reactExample === 'string'; const theme = document.documentElement.classList.contains('sl-theme-dark') ? 'dark' : 'light'; const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; const isDark = theme === 'dark' || (theme === 'auto' && prefersDark); const editors = isReact ? '0010' : '1000'; let htmlTemplate = ''; let jsTemplate = ''; let cssTemplate = ''; const form = document.createElement('form'); form.action = 'https://codepen.io/pen/define'; form.method = 'POST'; form.target = '_blank'; // HTML templates if (!isReact) { htmlTemplate = `\n` + `\n${htmlExample}`; jsTemplate = ''; } // React templates if (isReact) { htmlTemplate = '
'; jsTemplate = `import React from 'https://esm.sh/react@${reactVersion}';\n` + `import ReactDOM from 'https://esm.sh/react-dom@${reactVersion}';\n` + `import { setBasePath } from 'https://esm.sh/@shoelace-style/shoelace@${shoelaceVersion}/${cdndir}/utilities/base-path';\n` + `\n` + `// Set the base path for Shoelace assets\n` + `setBasePath('https://esm.sh/@shoelace-style/shoelace@${shoelaceVersion}/${npmdir}/')\n` + `\n${convertModuleLinks(reactExample)}\n` + `\n` + `ReactDOM.render(, document.getElementById('root'));`; } // CSS templates cssTemplate = `@import 'https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@${shoelaceVersion}/${cdndir}/themes/${ isDark ? 'dark' : 'light' }.css';\n` + '\n' + 'body {\n' + ' font: 16px sans-serif;\n' + ' background-color: var(--sl-color-neutral-0);\n' + ' color: var(--sl-color-neutral-900);\n' + ' padding: 1rem;\n' + '}'; // Docs: https://blog.codepen.io/documentation/prefill/ const data = { title: '', description: '', tags: ['shoelace', 'web components'], editors, head: ``, html_classes: `sl-theme-${isDark ? 'dark' : 'light'}`, css_external: ``, js_external: ``, js_module: true, js_pre_processor: isReact ? 'babel' : 'none', html: htmlTemplate, css: cssTemplate, js: jsTemplate }; const input = document.createElement('input'); input.type = 'hidden'; input.name = 'data'; input.value = JSON.stringify(data); form.append(input); document.documentElement.append(form); form.submit(); form.remove(); } }); // Set the initial flavor window.addEventListener('turbo:load', syncFlavor); })();