{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "gamification-kit",
  "title": "Gamification Kit",
  "author": "ilinxa",
  "description": "Shared helpers for team gamification components — a numeric clamp, name-to-initials resolution, and a stable latest-value ref hook.",
  "files": [
    {
      "path": "src/registry/components/gamification/_shared/gamification-kit/clamp.ts",
      "content": "/**\n * Generic numeric clamp — `Math.min(Math.max(n, lo), hi)`. Pure,\n * framework-free, SSR-safe. Extracted 2026-08-11 (P3.5 / D-04) from\n * byte-identical private copies in `team-challenge/lib/derive.ts` and\n * `team-progress-bar/lib/resolve-progress.ts`.\n */\nexport function clamp(n: number, lo: number, hi: number): number {\n  return Math.min(Math.max(n, lo), hi);\n}\n",
      "type": "registry:component",
      "target": "components/_shared/gamification-kit/clamp.ts"
    },
    {
      "path": "src/registry/components/gamification/_shared/gamification-kit/initials.ts",
      "content": "/**\n * First letters of up to two name words → avatar initials fallback.\n * Empty (or whitespace-only) input returns `\"?\"`; a single word returns its\n * first two characters; two-or-more words return the first character of the\n * first word + the first character of the last word — all uppercased. Pure,\n * framework-free, SSR-safe, deterministic.\n *\n * Extracted 2026-08-11 (P3.5 / D-04) from two behaviorally-identical private\n * copies: `team-challenge/parts/team-member-stack.tsx`'s `initials(name)` and\n * `team-task-claim/lib/members.ts`'s `initialsFor(member, fallbackId)` (the\n * latter is a member-resolution wrapper that now calls this core directly).\n */\nexport function initialsFromName(name: string): string {\n  const trimmed = name.trim();\n  if (trimmed === \"\") return \"?\";\n  const parts = trimmed.split(/\\s+/).filter(Boolean);\n  if (parts.length === 1) return parts[0]!.slice(0, 2).toUpperCase();\n  return (parts[0]![0]! + parts[parts.length - 1]![0]!).toUpperCase();\n}\n",
      "type": "registry:component",
      "target": "components/_shared/gamification-kit/initials.ts"
    },
    {
      "path": "src/registry/components/gamification/_shared/gamification-kit/use-latest-ref.ts",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\n/**\n * Keep a ref in sync with the latest `value`, assigned inside a `useEffect`\n * (never during render — not a `setState`, so it stays StrictMode-safe).\n * Read `.current` from event handlers, timers, or other effects so a fresh\n * inline callback/prop (a new identity every render) never has to be a\n * dependency of — and never re-subscribes — an observer/listener/timer keyed\n * on other, more stable deps.\n *\n * Extracted 2026-08-11 (P3.5 / D-04) from ~15 independent copies of this\n * exact idiom across the pack's headless `Root` providers and telemetry\n * hooks (`const xRef = useRef(x); useEffect(() => { xRef.current = x; })`,\n * with or without an explicit `[x]` dependency array — both variants\n * converge to the same steady-state ref value, so a single shared\n * implementation running every render is a strict, behavior-preserving\n * superset of both).\n */\nexport function useLatestRef<T>(value: T): React.RefObject<T> {\n  const ref = React.useRef(value);\n  React.useEffect(() => {\n    ref.current = value;\n  });\n  return ref;\n}\n",
      "type": "registry:component",
      "target": "components/_shared/gamification-kit/use-latest-ref.ts"
    },
    {
      "path": "src/registry/components/gamification/_shared/gamification-kit/index.ts",
      "content": "// gamification-kit — shared helpers deduplicated across the 6 `team-*` /\n// gamification pro-components (P3.5 / D-04). Support item, not a catalog\n// component: no `meta.ts`, no demo. See each module for its extraction note.\nexport { clamp } from \"./clamp\";\nexport { initialsFromName } from \"./initials\";\nexport { useLatestRef } from \"./use-latest-ref\";\n",
      "type": "registry:component",
      "target": "components/_shared/gamification-kit/index.ts"
    }
  ],
  "categories": [
    "gamification",
    "primitive"
  ],
  "type": "registry:block"
}