{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "use-stickies-clipboard",
  "title": "useStickiesClipboard",
  "author": "Stickies <https://stickies.live>",
  "description": "Copy, cut and paste notes in the Stickies format, so they paste into any app and come back whole.",
  "registryDependencies": [
    "https://stickies.live/r/stickies-format.json"
  ],
  "files": [
    {
      "path": "registry/stickies/hooks/use-stickies-clipboard.ts",
      "content": "\"use client\"\n\nimport { type RefObject, useCallback, useEffect, useRef } from \"react\"\nimport {\n  fromHtml,\n  fromObsidianCanvas,\n  fromText,\n  notesOf,\n  OBSIDIAN_CANVAS_MIME,\n  parseDocument,\n  STICKIES_MIME,\n  type StickiesDocument,\n  type StickiesSource,\n  type StickyNoteData,\n  toDocument,\n  toHtml,\n  toObsidianCanvas,\n  toText,\n} from \"@/registry/stickies/lib/stickies-format\"\n\nexport interface StickiesClipboardPaste {\n  notes: StickyNoteData[]\n  /** The full document, when the clipboard carried one; null for plain text. */\n  document: StickiesDocument | null\n}\n\n/**\n * The richest Stickies content in a clipboard or drop: the Stickies JSON, then cards copied\n * from Obsidian's canvas, then the document in the HTML's `data-stickies`, then plain text as\n * one note per paragraph.\n */\nexport function readStickies(data: DataTransfer, { allowText = true }: { allowText?: boolean } = {}): StickiesClipboardPaste | null {\n  const doc =\n    parseDocument(data.getData(STICKIES_MIME)) ?? fromObsidianCanvas(data.getData(OBSIDIAN_CANVAS_MIME)) ?? fromHtml(data.getData(\"text/html\"))\n  if (doc) return { notes: notesOf(doc), document: doc }\n  if (!allowText) return null\n  const notes = fromText(data.getData(\"text/plain\"))\n  return notes.length ? { notes, document: null } : null\n}\n\n/**\n * Writes notes as Stickies JSON, HTML and plain text, inside a copy, cut or drag event. Also\n * as Obsidian's canvas type, so they paste into an Obsidian canvas as cards.\n */\nexport function writeStickies(data: DataTransfer, notes: StickyNoteData[], source?: StickiesSource) {\n  const doc = toDocument(notes, { source })\n  data.setData(\"text/plain\", toText(notes))\n  data.setData(\"text/html\", toHtml(doc))\n  data.setData(STICKIES_MIME, JSON.stringify(doc))\n  data.setData(OBSIDIAN_CANVAS_MIME, toObsidianCanvas(doc))\n}\n\n/** True while someone is typing, when copy and paste belong to the text. */\nfunction editing() {\n  const el = document.activeElement\n  if (!(el instanceof HTMLElement)) return false\n  return el.isContentEditable || el instanceof HTMLTextAreaElement || (el instanceof HTMLInputElement && ![\"button\", \"checkbox\", \"radio\"].includes(el.type))\n}\n\nexport interface UseStickiesClipboardOptions {\n  /** The notes ⌘C and ⌘X take: usually the selection. */\n  getNotes: () => StickyNoteData[]\n  /** Pasted notes, with their original positions and IDs. Use `placeNotes` to put them on the board. */\n  onPaste: (paste: StickiesClipboardPaste) => void\n  /** After ⌘X has copied the notes: remove them. */\n  onCut?: (notes: StickyNoteData[]) => void\n  /** Recorded in what's copied, so other apps know where the notes came from. */\n  source?: StickiesSource\n  /** Make notes from pasted plain text, one per paragraph. On by default. */\n  pasteText?: boolean\n  /** Only while focus is in this element, or on nothing in particular. */\n  scope?: RefObject<HTMLElement | null>\n  enabled?: boolean\n}\n\n/**\n * ⌘C, ⌘X and ⌘V for notes, in the Stickies format. Copying writes all three versions the\n * spec lists, so notes paste into any app; pasting takes the richest one there. Typing in\n * a note or a field is left alone.\n */\nexport function useStickiesClipboard(options: UseStickiesClipboardOptions) {\n  const latest = useRef(options)\n  latest.current = options\n  const enabled = options.enabled ?? true\n\n  useEffect(() => {\n    if (!enabled) return\n    const active = () => {\n      if (editing()) return false\n      const scope = latest.current.scope?.current\n      const el = document.activeElement\n      return !scope || !el || el === document.body || scope.contains(el)\n    }\n    // An event another board (or anything else) has taken is left alone.\n    const copy = (cut: boolean) => (e: ClipboardEvent) => {\n      if (e.defaultPrevented || !e.clipboardData || !active()) return\n      const notes = latest.current.getNotes()\n      if (notes.length === 0) return\n      e.preventDefault()\n      writeStickies(e.clipboardData, notes, latest.current.source)\n      if (cut) latest.current.onCut?.(notes)\n    }\n    const onCopy = copy(false)\n    const onCut = copy(true)\n    const onPaste = (e: ClipboardEvent) => {\n      if (e.defaultPrevented || !e.clipboardData || !active()) return\n      const paste = readStickies(e.clipboardData, { allowText: latest.current.pasteText ?? true })\n      if (!paste || paste.notes.length === 0) return\n      e.preventDefault()\n      latest.current.onPaste(paste)\n    }\n    document.addEventListener(\"copy\", onCopy)\n    document.addEventListener(\"cut\", onCut)\n    document.addEventListener(\"paste\", onPaste)\n    return () => {\n      document.removeEventListener(\"copy\", onCopy)\n      document.removeEventListener(\"cut\", onCut)\n      document.removeEventListener(\"paste\", onPaste)\n    }\n  }, [enabled])\n\n  /**\n   * Copies notes from a button or menu, outside a copy event. Browsers only allow HTML and\n   * plain text there, so other apps read the notes from the HTML's `data-stickies`.\n   */\n  const copy = useCallback(async (notes: StickyNoteData[]) => {\n    const doc = toDocument(notes, { source: latest.current.source })\n    const text = toText(notes)\n    if (typeof ClipboardItem !== \"undefined\" && navigator.clipboard?.write) {\n      await navigator.clipboard.write([\n        new ClipboardItem({\n          \"text/html\": new Blob([toHtml(doc)], { type: \"text/html\" }),\n          \"text/plain\": new Blob([text], { type: \"text/plain\" }),\n        }),\n      ])\n    } else {\n      await navigator.clipboard.writeText(text)\n    }\n  }, [])\n\n  return { copy }\n}\n",
      "type": "registry:hook"
    }
  ],
  "docs": "See https://stickies.live/docs#use-stickies-clipboard for usage.",
  "categories": [
    "stickies"
  ],
  "type": "registry:hook"
}