UNPKG

@reallyland/really-elements

Version:

A collection of opinionated custom elements for the web

134 lines (133 loc) 4.8 kB
import { __decorate } from "tslib"; import { css, html, LitElement } from 'lit'; import { property, query } from 'lit/decorators.js'; function toCopyNode(node, contentValue, noTextNode = false) { let preNode = node; if (noTextNode) { preNode = document.createElement('pre'); preNode.textContent = contentValue; preNode.style.position = 'absolute'; preNode.style.top = preNode.style.left = '200vh'; preNode.style.opacity = '0'; document.body.appendChild(preNode); } return { node: preNode, temporary: noTextNode }; } export class ClipboardCopy extends LitElement { constructor() { super(...arguments); this.forSlot = 'copy-for'; this.idSlot = 'copy-id'; this._idElement = null; } static { this.styles = [ css ` :host { display: block; } * { box-sizing: border-box; } `, ]; } render() { return html `<slot @slotchange="${this._assignSlotted}"></slot>`; } _assignSlotted() { const slot = this._slot; if (slot) { const forSlot = this.forSlot; const idSlot = this.idSlot; const nodes = slot.assignedNodes(); const slotted = nodes.reduce((p, n) => { if ((p.for && p.id) || n.nodeType !== Node.ELEMENT_NODE) return p; const isIdSlot = n.hasAttribute(idSlot); const isForSlot = n.hasAttribute(forSlot); const isIdSlotNull = p.id == null; const isForSlotNull = p.for == null; if (isIdSlot && isIdSlotNull) { p.id = n; } else if (isForSlot && isForSlotNull) { p.for = n; } else { const forElement = isForSlotNull ? n.querySelector(`[${forSlot}]`) : null; const idElement = isIdSlotNull ? n.querySelector(`[${idSlot}]`) : null; if (forElement) p.for = forElement; if (idElement) p.id = idElement; } return p; }, { id: null, for: null }); const forSlotted = slotted.for; if (forSlotted) forSlotted.addEventListener('click', () => this._copyText()); this._idElement = slotted.id; } } _copyText() { let copySuccess = false; let contentValue = ''; try { const idElement = this._idElement; if (idElement == null) { throw new Error(`No element matches 'idSlot' is found`); } const isInputElement = idElement instanceof HTMLInputElement; const isTextareaElement = idElement instanceof HTMLTextAreaElement; const isAnchorElement = idElement instanceof HTMLAnchorElement; contentValue = (isInputElement || isTextareaElement ? idElement.value : isAnchorElement ? idElement.href : idElement.textContent) || ''; const nodeObj = toCopyNode(idElement, contentValue, isInputElement || isTextareaElement || isAnchorElement); const copyNode = nodeObj.node; const selection = getSelection(); const range = document.createRange(); selection?.removeAllRanges(); range.selectNodeContents(copyNode); selection?.addRange(range); copySuccess = document.execCommand('copy'); selection?.removeAllRanges(); if (nodeObj.temporary) document.body.removeChild(copyNode); if (!copySuccess) throw new Error('Failed to copy'); } catch (reason) { this.dispatchEvent(new CustomEvent('copy-error', { detail: { reason: reason }, bubbles: true, composed: true, })); } finally { if (copySuccess) { this.dispatchEvent(new CustomEvent('copy-success', { detail: { value: contentValue }, bubbles: true, composed: true, })); } } } } __decorate([ property({ type: String }) ], ClipboardCopy.prototype, "forSlot", void 0); __decorate([ property({ type: String }) ], ClipboardCopy.prototype, "idSlot", void 0); __decorate([ query('slot') ], ClipboardCopy.prototype, "_slot", void 0); //# sourceMappingURL=clipboard-copy.js.map