import { html, css, LitElement } from "lit"; import { customElement, property, query } from "lit/decorators.js"; @customElement("rich-viewer") export class RichViewer extends LitElement { static styles = css` article { padding: var(--rich-padding); width: calc(100% - var(--rich-padding) * 2); height: calc(100% - var(--rich-padding) * 2); } article[contenteditable="true"] { border: none; outline: none; } `; @query("#content") content!: HTMLDivElement; @property({ type: Boolean }) readonly = false; @property({ type: Object, hasChanged: () => true }) node!: Element; render() { const { readonly, node } = this; return html`
this.updateSelection()} > ${node}
`; } updateSelection() { // @ts-ignore const shadowSelection = this.shadowRoot?.getSelection ? // @ts-ignore this.shadowRoot!.getSelection() : null; const selection = shadowSelection || document.getSelection() || window.getSelection(); this.dispatchEvent( new CustomEvent("selection", { detail: selection, bubbles: true, composed: true, }) ); } firstUpdated() { document.execCommand("defaultParagraphSeparator", false, "br"); document.addEventListener("selectionchange", () => { this.updateSelection(); }); window.addEventListener("selectionchange", () => { this.updateSelection(); }); document.addEventListener("keydown", () => { this.updateSelection(); }); } } declare global { interface HTMLElementTagNameMap { "rich-viewer": RichViewer; } }