UNPKG

monogon

Version:

Modern syntax highlighting for developer tooling

99 lines 3.56 kB
import { transformModule } from './utils.js'; import { getModule } from './modules.js'; import { css } from './theme.js'; class MonogonCode extends HTMLElement { constructor() { super(); Object.defineProperty(this, "value", { enumerable: true, configurable: true, writable: true, value: '' }); Object.defineProperty(this, "codeEl", { enumerable: true, configurable: true, writable: true, value: null }); Object.defineProperty(this, "styleEl", { enumerable: true, configurable: true, writable: true, value: null }); Object.defineProperty(this, "applyHighlights", { enumerable: true, configurable: true, writable: true, value: () => { } }); } async connectedCallback() { await this.prepare(); setTimeout(() => { this.refresh(); }, 1); // TODO: handle with element creation order better } async attributeChangedCallback(oldValue, newValue) { if (oldValue !== newValue) { await this.refresh(); } } async prepare() { const shadow = this.shadowRoot || this.attachShadow({ mode: 'open' }); shadow.innerHTML = ''; /** Style */ const themeStyleEl = document.createElement('style'); themeStyleEl.textContent = css; shadow.appendChild(themeStyleEl); const preEl = document.createElement('pre'); const codeEl = document.createElement('code'); const editable = this.hasAttribute('readonly') ? 'false' : 'plaintext-only'; codeEl.setAttribute('contenteditable', editable); codeEl.setAttribute('spellcheck', 'false'); shadow.appendChild(preEl); preEl.appendChild(codeEl); /** Listeners */ codeEl.addEventListener('input', () => { this.codeEl.normalize(); this.value = this.codeEl.textContent ?? ''; this.applyHighlights(); }); this.codeEl = codeEl; this.styleEl = themeStyleEl; } async refresh() { if (!this.codeEl) return; /** Module */ const moduleName = this.getAttribute('lang') ?? 'plaintext'; const module = await getModule(moduleName); const content = this.getAttribute('content') ?? ''; this.value = content; this.codeEl.textContent = module.format ? module.format(content) : content; // When having multiple blocks on the same page, generated highlights will conflict with each other if (!this.codeEl.childNodes?.[0]) return; const littleHash = window.crypto.randomUUID().substring(0, 6); const definitions = transformModule(module.definitions, this.codeEl, littleHash); const moduleCss = definitions.map((m) => m.css).join(' '); /** Highlights */ this.styleEl.textContent += `${moduleCss}`; this.applyHighlights = () => { definitions.forEach((highlight) => { highlight.apply(); }); }; this.applyHighlights(); } } Object.defineProperty(MonogonCode, "observedAttributes", { enumerable: true, configurable: true, writable: true, value: ['content', 'lang', 'readonly'] }); if (!customElements.get('monogon-code')) customElements.define('monogon-code', MonogonCode); //# sourceMappingURL=monogon-code.js.map