{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sk-analytics",
  "type": "registry:hook",
  "title": "Self-instrumentation hook",
  "description": "useSkBlock gives a block its data-sk-* attributes and emits view, interact and convert events to any analytics sink already on the page (GA4 dataLayer, PostHog, Clarity, Shopify, rrweb).",
  "author": "StoreKit <hello@storekit.dev>",
  "categories": [
    "ui"
  ],
  "dependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "lib/sk-analytics.ts",
      "content": "\"use client\"\n\nimport { useEffect, useRef } from \"react\"\n\n/* Self-instrumenting components.\n   Every StoreKit block carries data-sk-section and data-sk-variant on its root.\n   This hook fires \"view\" once (50% visible) and lets a block report \"interact\"\n   and \"convert\" events. Events go to every sink that exists on the page:\n   window.dataLayer (GA4 / GTM), posthog, clarity, Shopify analytics, rrweb\n   custom events, and a window.__sk listener array for your own code.\n   Nothing is sent anywhere by default; sinks are detected, not installed. */\n\nexport type SkEvent = {\n  type: \"view\" | \"interact\" | \"convert\"\n  section: string\n  variant: string\n  pos?: number\n  exp?: string\n  label?: string\n  value?: number\n  ts: number\n}\n\ndeclare global {\n  interface Window {\n    dataLayer?: unknown[]\n    posthog?: { capture: (name: string, props?: Record<string, unknown>) => void }\n    clarity?: (...args: unknown[]) => void\n    Shopify?: { analytics?: { publish?: (name: string, payload?: unknown) => void } }\n    rrweb?: { record?: { addCustomEvent?: (tag: string, payload: unknown) => void } }\n    __sk?: Array<(e: SkEvent) => void>\n  }\n}\n\nexport function skEmit(e: Omit<SkEvent, \"ts\">) {\n  if (typeof window === \"undefined\") return\n  const ev: SkEvent = { ...e, ts: Date.now() }\n  try { window.dataLayer?.push({ event: `sk_${ev.type}`, ...ev }) } catch {}\n  try { window.posthog?.capture(`sk_${ev.type}`, ev) } catch {}\n  try { window.clarity?.(\"event\", `sk_${ev.type}_${ev.section}_${ev.variant}`) } catch {}\n  try { window.Shopify?.analytics?.publish?.(`sk_${ev.type}`, ev) } catch {}\n  try { window.rrweb?.record?.addCustomEvent?.(\"sk\", ev) } catch {}\n  try { window.__sk?.forEach((fn) => fn(ev)) } catch {}\n}\n\n/** Attach to a block's root. Returns the data attributes and an `emit` helper.\n    The observer is (re)attached after every render until the root exists, so\n    roots that mount later (drawers, modals) still fire their view event. */\nexport function useSkBlock(section: string, variant: string, opts: { pos?: number; exp?: string } = {}) {\n  const ref = useRef<HTMLElement | null>(null)\n  const seen = useRef(false)\n  const observed = useRef<HTMLElement | null>(null)\n  const io = useRef<IntersectionObserver | null>(null)\n  useEffect(() => {\n    const el = ref.current\n    if (!el || seen.current || observed.current === el || typeof IntersectionObserver === \"undefined\") return\n    io.current?.disconnect()\n    observed.current = el\n    const obs = new IntersectionObserver(\n      (entries) => {\n        if (entries.some((x) => x.isIntersecting) && !seen.current) {\n          seen.current = true\n          skEmit({ type: \"view\", section, variant, pos: opts.pos, exp: opts.exp })\n          obs.disconnect()\n        }\n      },\n      { threshold: 0.5 }\n    )\n    obs.observe(el)\n    io.current = obs\n  })\n  useEffect(() => () => io.current?.disconnect(), [])\n  const emit = (type: \"interact\" | \"convert\", label?: string, value?: number) =>\n    skEmit({ type, section, variant, pos: opts.pos, exp: opts.exp, label, value })\n  const attrs = { \"data-sk-section\": section, \"data-sk-variant\": variant, \"data-sk-pos\": opts.pos, \"data-sk-exp\": opts.exp } as const\n  return { ref, attrs, emit }\n}\n",
      "type": "registry:lib",
      "target": "components/storekit/lib/sk-analytics.ts"
    }
  ],
  "docs": "const { ref, attrs, emit } = useSkBlock(\"pdp\", \"buybox\"); spread attrs on the root, call emit(\"convert\", \"add_to_cart\", amount) on the action.",
  "meta": {
    "section": "ui"
  }
}