UNPKG

drab

Version:

Interactivity for You

100 lines (87 loc) 2.03 kB
import { Announce, Content, type ContentAttributes, Lifecycle, Trigger, type TriggerAttributes, } from "../base/index.js"; export type ShareAttributes = TriggerAttributes & ContentAttributes & ( | { /** Share URL */ url: string; /** `ShareData` text (only supported on some targets) */ text?: string; /** Share title */ "share-title"?: string; } | { /** Text to copy */ text: string; } ); /** * Uses the * [Navigator API](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share) * to share the `url` if `navigator.share` is supported. * * Otherwise uses the * [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText) * to copy the `url` or `text` provided. * * ### Attributes * * `url` * * URL to share. * * `text` * * Text to copy, or the `ShareData` text if `url` is set (only supported on some targets). * * `share-title` * * `ShareData` title (only supported on some targets). */ export class Share extends Lifecycle(Trigger(Content(Announce()))) { constructor() { super(); } // helper since ShareData expects undefined instead of null #attrOrUndefined(name: string) { return this.getAttribute(name) ?? undefined; } get #title() { return this.#attrOrUndefined("share-title"); } get #text() { return this.#attrOrUndefined("text"); } get #url() { return this.#attrOrUndefined("url"); } override mount() { this.listener(() => { const data: ShareData = { title: this.#title, text: this.#text, url: this.#url, }; if (data.url && navigator.canShare && navigator.canShare(data)) { return navigator.share(data).catch((e) => { // catch abort errors when user cancels the share if (!(e instanceof Error) || e.name !== "AbortError") throw e; }); } const copy = data.url || data.text; if (copy) { return navigator.clipboard.writeText(copy).then(() => { this.announce("copied to clipboard"); this.swap(); }); } }); } }