{
  "$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": [
    "lucide-react-native@^1.21.0"
  ],
  "registryDependencies": [
    "@kit-native/icon",
    "@kit-native/lib-haptics",
    "@kit-native/lib-utils",
    "@kit-native/text"
  ],
  "files": [
    {
      "path": "components/kit/value-header.tsx",
      "content": "import { Icon } from '@/components/ui/icon';\nimport { Text } from '@/components/ui/text';\nimport { haptic } from '@/lib/haptics';\nimport { cn } from '@/lib/utils';\nimport { EyeIcon, EyeOffIcon } from 'lucide-react-native';\nimport * as React from 'react';\nimport { Pressable, View } from 'react-native';\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: Record<NonNullable<Props['captionTone']>, string> = {\n  default: 'text-muted-foreground',\n  positive: 'text-success',\n  negative: 'text-destructive',\n};\n\n/**\n * The hero number at the top of a screen — a balance, a total, a score.\n *\n * `maskable` adds the eye toggle that replaces the figure with dots, for anything\n * someone might not want visible over their shoulder.\n */\nexport function ValueHeader({\n  value,\n  label,\n  caption,\n  captionTone = 'default',\n  maskable,\n  masked,\n  onMaskedChange,\n  align = 'start',\n  className,\n}: Props) {\n  const [ownMasked, setOwnMasked] = React.useState(false);\n  const isMasked = masked ?? ownMasked;\n\n  const toggle = () => {\n    haptic('selection');\n    const next = !isMasked;\n    if (masked === undefined) setOwnMasked(next);\n    onMaskedChange?.(next);\n  };\n\n  return (\n    <View className={cn('gap-1', align === 'center' && 'items-center', className)}>\n      {label ? <Text className=\"text-muted-foreground text-sm font-medium\">{label}</Text> : null}\n      <View className=\"flex-row items-center gap-3\">\n        <Text className=\"text-4xl font-bold tracking-tight\" accessibilityLabel={isMasked ? 'Value hidden' : value}>\n          {isMasked ? '••••••' : value}\n        </Text>\n        {maskable ? (\n          <Pressable\n            onPress={toggle}\n            hitSlop={12}\n            accessibilityRole=\"button\"\n            accessibilityLabel={isMasked ? 'Show value' : 'Hide value'}\n            className=\"bg-muted size-8 items-center justify-center rounded-full active:opacity-70\">\n            <Icon as={isMasked ? EyeOffIcon : EyeIcon} size={16} className=\"text-muted-foreground\" />\n          </Pressable>\n        ) : null}\n      </View>\n      {/* Kept mounted while masked so the block does not change height. */}\n      {caption ? (\n        <Text className={cn('text-sm font-medium', CAPTION[captionTone], isMasked && 'opacity-0')}>{caption}</Text>\n      ) : null}\n    </View>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/kit/value-header.tsx"
    }
  ],
  "meta": {
    "exports": [
      "ValueHeader"
    ],
    "api": "<ValueHeader value label? caption? captionTone? maskable? align? />"
  },
  "docs": "Run `npx expo install --fix` afterwards so Expo SDK packages match your SDK. Needs the kit theme (`@kit-native/theme`) and `KitThemeProvider` from `@kit-native/lib-theme-context` at the root.",
  "categories": [
    "data"
  ],
  "type": "registry:component"
}