<code-block collapsed language="html" copy-success="Copied!" copy-error="Error trying to copy to clipboard!">
<p class="meta">
<span class="file">code-block.html</span>
<span class="language">html</span>
</p>
<pre><code class="language-html"><code-block collapsed language="html" copy-success="Copied!" copy-error="Error trying to copy to clipboard!">
<p class="meta">
<span class="file">code-block.html</span>
<span class="language">html</span>
</p>
<pre><code class="language-html"></code></pre>
<input-button class="copy">
<button type="button" class="secondary small">
<span class="label">Copy</span>
</button>
</input-button>
<button type="button" class="overlay">Expand</button>
</code-block></code></pre>
<input-button class="copy">
<button type="button" class="secondary small">
<span class="label">Copy</span>
</button>
</input-button>
<button type="button" class="overlay">Expand</button>
</code-block>
code-block {
position: relative;
display: block;
margin: 0 0 var(--space-l);
.meta {
display: flex;
margin-bottom: var(--space-xs);
font-size: var(--font-size-s);
color: var(--color-text-soft);
&:not(:has(.file)) .language {
margin-block-start: calc(-1 * var(--space-m));
}
}
.language {
margin-left: auto;
text-transform: uppercase;
}
& pre {
font-size: var(--font-size-s);
color: var(--color-gray-10);
background: var(--color-gray-90);
padding: var(--space-s);
margin: var(--space-xs) 0;
overflow: auto;
border-radius: var(--space-xs);
}
.copy {
position: absolute;
right: var(--space-s);
bottom: var(--space-s);
}
.overlay {
display: none;
}
&[collapsed] {
max-height: 12rem;
overflow: hidden;
&::after {
content: '';
display: block;
position: absolute;
bottom: 0;
width: 100%;
height: var(--space-m);
background: linear-gradient(-135deg, var(--color-secondary) 0.5rem, transparent 0) 0 0.5rem, linear-gradient(135deg, var(--color-secondary) 0.5rem, var(--color-background) 0) 0 0.5rem;
background-color: var(--color-secondary);
background-size: var(--space-m) var(--space-m);
background-position: bottom;
}
.copy {
display: none;
}
.overlay {
display: flex;
flex-direction: column-reverse;
align-items: center;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 6rem;
color: var(--color-text);
background: linear-gradient(transparent, var(--color-secondary));
border: 0;
cursor: pointer;
padding: var(--space-xs) var(--space-s);
margin-bottom: var(--space-m);
font-size: var(--font-size-s);
transition: background-color var(--transition-short) var(--easing-inout);
text-shadow: var(--color-background) 1px 0 var(--space-xs);
&:hover,
&:active {
text-shadow: var(--color-text-inverted) var(--space-xs) 0 var(--space-s);
}
}
}
}
import { asBoolean, toggleAttribute, UIElement } from '../../../'
// import Prism from 'prismjs'
// import 'prismjs/components/prism-bash';
// import 'prismjs/components/prism-json';
// import 'prismjs/components/prism-typescript';
import type { InputButton } from '../input-button/input-button'
export class CodeBlock extends UIElement<{ collapsed: boolean }> {
static readonly localName = 'code-block'
static observedAttributes = ['collapsed']
init = {
collapsed: asBoolean
}
connectedCallback() {
// Enhance code block with Prism.js
// const language = this.getAttribute('language') || 'html'
const content = this.querySelector('code')
if (content) {
/* this.set('code', content.textContent?.trim(), false)
effect(() => {
// Apply syntax highlighting while preserving Lit's marker nodes in Storybook
const code = document.createElement('code')
code.innerHTML = Prism.highlight(
this.get('code') ?? '',
Prism.languages[language],
language
)
enqueue(() => {
Array.from(code.childNodes)
.filter(node => node.nodeType !== Node.COMMENT_NODE)
.forEach(node => node.remove())
Array.from(code.childNodes)
.forEach(node => code.appendChild(node))
}, [code, 'h'])
}) */
// Copy to clipboard
this.first('.copy').on('click', async (e: Event) => {
const copyButton = e.currentTarget as InputButton
const label = copyButton.textContent ?? ''
let status = 'success'
try {
await navigator.clipboard.writeText(content.textContent ?? '')
} catch (err) {
console.error('Error when trying to use navigator.clipboard.writeText()', err)
status = 'error'
}
copyButton.set('disabled', true)
copyButton.set('label', this.getAttribute(`copy-${status}`) ?? label)
setTimeout(() => {
copyButton.set('disabled', false)
copyButton.set('label', label)
}, status === 'success' ? 1000 : 3000)
})
// Expand
this.first('.overlay').on('click', () => this.set('collapsed', false))
this.self.sync(toggleAttribute('collapsed'))
}
}
}
CodeBlock.define()