{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "value-header",
  "title": "Value header",
  "description": "hero figure + caption · `maskable` adds the eye toggle",
  "dependencies": [
    "cn@^0.4.0",
    "lucide-react@^1.52.0"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "components/kit/value-header.tsx",
      "content": "'use client';\nimport { cn } from 'cn';\nimport { EyeIcon, EyeOffIcon } from 'lucide-react';\nimport * as React from 'react';\n\ntype Props = {\n  /** The hero figure, already formatted: \"$60.00\", \"12,480 steps\". */\n  value: string;\n  /** Small label above the value. */\n  label?: string;\n  /** Line under the value: a delta, a date, a status. */\n  caption?: string;\n  captionTone?: 'default' | 'positive' | 'negative';\n  /** Offer the eye toggle that hides the value. */\n  maskable?: boolean;\n  /** Controlled mask state. Omit to let the component own it. */\n  masked?: boolean;\n  onMaskedChange?: (next: boolean) => void;\n  align?: 'start' | 'center';\n  className?: string;\n};\n\nconst CAPTION = { default: 'text-muted-foreground', positive: 'text-success', negative: 'text-destructive' } as const;\n\n/**\n * The hero number at the top of a page: a balance, a total, a score. `maskable` adds the eye toggle that replaces\n * the figure with dots, for anything someone might not want visible over their shoulder.\n */\nexport function ValueHeader({ value, label, caption, captionTone = 'default', maskable, masked, onMaskedChange, align = 'start', className }: Props) {\n  const [own, setOwn] = React.useState(false);\n  const isMasked = masked ?? own;\n  const toggle = () => {\n    const next = !isMasked;\n    if (masked === undefined) setOwn(next);\n    onMaskedChange?.(next);\n  };\n  return (\n    <div className={cn('flex flex-col gap-1', align === 'center' && 'items-center text-center', className)}>\n      {label ? <p className=\"text-muted-foreground text-sm font-medium\">{label}</p> : null}\n      <div className=\"flex items-center gap-3\">\n        <p className=\"text-4xl font-bold tracking-tight tabular-nums\">\n          {isMasked ? (\n            <>\n              <span aria-hidden>••••••</span>\n              <span className=\"sr-only\">Value hidden</span>\n            </>\n          ) : (\n            value\n          )}\n        </p>\n        {maskable ? (\n          <button\n            type=\"button\"\n            onClick={toggle}\n            aria-label={isMasked ? 'Show value' : 'Hide value'}\n            aria-pressed={isMasked}\n            className=\"bg-muted text-muted-foreground hover:text-foreground focus-visible:ring-ring/50 flex size-8 items-center justify-center rounded-full outline-none focus-visible:ring-[3px]\">\n            {isMasked ? <EyeOffIcon className=\"size-4\" aria-hidden /> : <EyeIcon className=\"size-4\" aria-hidden />}\n          </button>\n        ) : null}\n      </div>\n      {/* Kept while masked so the block does not change height. */}\n      {caption ? <p className={cn('text-sm font-medium', CAPTION[captionTone], isMasked && 'invisible')}>{caption}</p> : null}\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/kit/value-header.tsx"
    }
  ],
  "meta": {
    "exports": [
      "ValueHeader"
    ],
    "api": "<ValueHeader value label? caption? captionTone? maskable? align? />"
  },
  "docs": "Needs the kit theme (`@kit/theme`) and a next-themes ThemeProvider (attribute=\"class\") at the root.",
  "categories": [
    "data"
  ],
  "type": "registry:component"
}