import "@github/clipboard-copy-element"; import { css, html, LitElement, TemplateResult } from "lit"; import { customElement, property, query, queryAssignedNodes, state, } from "lit/decorators.js"; @customElement("permalink-edit") export class PermalinkEdit extends LitElement { @queryAssignedNodes("domain", true) _domain!: NodeListOf; @queryAssignedNodes("slug-input", true) _slugInput!: NodeListOf; @query("clipboard-copy") _clipboardCopy!: any; @property({ attribute: "edit-label" }) editLabel = "Edit"; @property({ attribute: "copy-label" }) copyLabel = "Copy"; @property({ attribute: "permalink-base" }) permalinkBase = ""; @state() isEditable = false; @state() permalink = ""; @state() slugInputEvents = [ { name: "change", onEvent: (): void => { this.setPermalink(); }, }, { name: "focus", onEvent: (): void => { this.editSlug(); }, }, { name: "focusin", onEvent: (event: Event): void => { setTimeout(() => { (event.target as HTMLInputElement).selectionStart = ( event.target as HTMLInputElement ).selectionEnd = 10000; }, 0); }, }, { name: "focusout", onEvent: (): void => { this.stopEdit(); }, }, ]; connectedCallback(): void { super.connectedCallback(); } firstUpdated(): void { this.permalinkBase += this.permalinkBase.endsWith("/") ? "" : "/"; // set permalink value this.setPermalink(); this._clipboardCopy.addEventListener("clipboard-copy", (event: Event) => { const notice = (event.target as HTMLDivElement).querySelector( ".notice" ) as HTMLSpanElement; if (notice) { notice.hidden = false; setTimeout(() => { notice.hidden = true; }, 1000); } }); this._slugInput[0].readOnly = !this.isEditable; this.slugInputEvents.forEach((slugInputEvent) => { this._slugInput[0].addEventListener( slugInputEvent.name, slugInputEvent.onEvent ); }); } disconnectedCallback(): void { super.disconnectedCallback(); this.slugInputEvents.forEach((slugInputEvent) => { this._slugInput[0].removeEventListener( slugInputEvent.name, slugInputEvent.onEvent ); }); this._clipboardCopy.removeEventListener( "clipboard-copy", (event: Event) => { const notice = (event.target as HTMLDivElement).querySelector( ".notice" ) as HTMLSpanElement; if (notice) { notice.hidden = false; setTimeout(() => { notice.hidden = true; }, 1000); } } ); } editSlug(): void { this.isEditable = true; this._slugInput[0].readOnly = !this.isEditable; this._slugInput[0].focus(); } stopEdit(): void { this.isEditable = false; this._slugInput[0].readOnly = !this.isEditable; } setPermalink(): void { this.permalink = this.permalinkBase + this._slugInput[0].value; } static styles = css` ::slotted(input[slot="slug-input"][readonly]) { background-color: transparent !important; border-color: transparent !important; padding-left: 0 !important; margin-left: -0.25rem !important; font-weight: 600; } ::slotted([slot="domain"]) { margin-right: 0.25rem; } button, clipboard-copy { background: transparent; border: none; padding: 0.25rem; cursor: pointer; } button svg, clipboard-copy svg { fill: hsl(var(--color-text-base)); opacity: 0.6; font-size: 1.25rem; } button:hover svg, clipboard-copy:hover svg { opacity: 1; } clipboard-copy { position: relative; } .notice { position: absolute; background-color: black; color: #ffffff; bottom: -1rem; right: 0; font-size: 0.75rem; padding: 0 0.25rem; } `; render(): TemplateResult<1> { return html`${this .isEditable ? "" : html` `} `; } }