{"version":3,"file":"ngwr-clipboard.mjs","sources":["../../../projects/lib/clipboard/clipboard.ts","../../../projects/lib/clipboard/ngwr-clipboard.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { DOCUMENT } from '@angular/common';\nimport { Service, inject } from '@angular/core';\n\nimport type { WrClipboardPermission } from './interfaces';\n\n/**\n * Programmatic clipboard read / write.\n *\n * - **Write** uses `navigator.clipboard.writeText` with a hidden\n *   `<textarea>` + `execCommand('copy')` fallback for non-secure contexts.\n * - **Read** uses `navigator.clipboard.readText` (no fallback — older\n *   browsers expose no equivalent).\n * - **Available** / **permission** check what the current browser allows\n *   so UI can disable the action when it would silently no-op.\n *\n * SSR-safe: every method short-circuits when there's no `document.defaultView`.\n *\n * @example\n * ```ts\n * const clip = inject(WrClipboard);\n *\n * await clip.write('Hello');           // resolves to true on success\n * const text = await clip.read();      // string | null\n * clip.available();                    // boolean\n * await clip.permission('write');      // 'granted' | 'denied' | 'prompt' | 'unsupported'\n * ```\n *\n * @see https://ngwr.dev/services/clipboard\n */\n@Service()\nexport class WrClipboard {\n  private readonly doc = inject(DOCUMENT);\n\n  /** Is any clipboard write path available (async API or `execCommand`)? */\n  available(): boolean {\n    const view = this.doc.defaultView;\n    if (!view) return false;\n    if (view.navigator?.clipboard) return true;\n    return typeof this.doc.execCommand === 'function';\n  }\n\n  /**\n   * Write text. Resolves to `true` on success, `false` on failure (denied\n   * permission, no clipboard, etc).\n   */\n  async write(text: string): Promise<boolean> {\n    const view = this.doc.defaultView;\n    if (!view) return false;\n\n    try {\n      if (view.navigator?.clipboard) {\n        await view.navigator.clipboard.writeText(text);\n        return true;\n      }\n      return this.legacyWrite(text);\n    } catch {\n      return this.legacyWrite(text);\n    }\n  }\n\n  /**\n   * Read text from the clipboard. Returns `null` when unsupported or\n   * when the user denied the permission prompt.\n   */\n  async read(): Promise<string | null> {\n    const view = this.doc.defaultView;\n    if (!view?.navigator?.clipboard?.readText) return null;\n    try {\n      return await view.navigator.clipboard.readText();\n    } catch {\n      return null;\n    }\n  }\n\n  /**\n   * Report whether clipboard read / write is available and, when the\n   * browser exposes it, what the user has granted.\n   *\n   * The answer is grounded in the actual Clipboard API capability\n   * (`writeText` / `readText`), then refined by the Permissions API when\n   * it can speak for the requested name. `clipboard-read` / `clipboard-write`\n   * are not recognised everywhere — Firefox and Safari throw on the query —\n   * so a missing or throwing Permissions API is treated as \"supported,\n   * will resolve at use time\" (`'prompt'`), not `'unsupported'`. We only\n   * return `'unsupported'` when the capability genuinely isn't there.\n   */\n  async permission(name: 'read' | 'write'): Promise<WrClipboardPermission> {\n    const view = this.doc.defaultView;\n    if (!view) return 'unsupported';\n\n    const clipboard = view.navigator?.clipboard;\n    const capable =\n      name === 'write'\n        ? typeof clipboard?.writeText === 'function' || typeof this.doc.execCommand === 'function'\n        : typeof clipboard?.readText === 'function';\n    if (!capable) return 'unsupported';\n\n    // Capability exists; ask the Permissions API to refine the state when it can.\n    if (typeof view.navigator?.permissions?.query !== 'function') return 'prompt';\n    try {\n      const status = await view.navigator.permissions.query({\n        name: `clipboard-${name}` as PermissionName,\n      });\n      return status.state;\n    } catch {\n      // Name not recognised by this browser — capability is still present.\n      return 'prompt';\n    }\n  }\n\n  // Internals\n\n  /** Hidden-textarea + `execCommand('copy')` write. Synchronous, no permissions. */\n  private legacyWrite(text: string): boolean {\n    const node = this.doc.createElement('textarea');\n    node.value = text;\n    node.setAttribute('readonly', '');\n    node.style.position = 'fixed';\n    node.style.top = '0';\n    node.style.left = '0';\n    node.style.opacity = '0';\n    node.style.pointerEvents = 'none';\n    this.doc.body.appendChild(node);\n    node.select();\n    try {\n      return this.doc.execCommand('copy');\n    } catch {\n      return false;\n    } finally {\n      this.doc.body.removeChild(node);\n    }\n  }\n}\n\nexport type { WrClipboardPermission } from './interfaces';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}