{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "context",
  "title": "Context",
  "description": "AI Elements context/usage display (Partial usage type).",
  "dependencies": [
    "tokenlens"
  ],
  "registryDependencies": [
    "button",
    "hover-card",
    "progress"
  ],
  "files": [
    {
      "path": "components/ai-elements/context.tsx",
      "content": "\"use client\";\n\nimport { Button } from \"@/components/ui/button\";\nimport {\n  HoverCard,\n  HoverCardContent,\n  HoverCardTrigger,\n} from \"@/components/ui/hover-card\";\nimport { Progress } from \"@/components/ui/progress\";\nimport { cn } from \"@/lib/utils\";\nimport type { ComponentProps } from \"react\";\nimport { createContext, useContext, useMemo } from \"react\";\nimport { getUsage } from \"tokenlens\";\n\nconst PERCENT_MAX = 100;\nconst ICON_RADIUS = 10;\n\n// Open/close instantly. Radix's HoverCard takes these; Base UI's PreviewCard —\n// what the shadcn CLI swaps in on a Base UI project — has neither, so naming\n// them inline fails to typecheck there (\"Property 'openDelay' does not exist on\n// type 'Props<unknown>'\"). Spreading keeps the zero-delay behaviour on the\n// supported Radix base and is inert on Base UI. Measured: this was 1 of the 13\n// Base UI errors, and the only one in a file this kit ships (bd\n// mastra-chat-kit-68j) — the other 12 are upstream's to fix.\nconst NO_DELAY = { closeDelay: 0, openDelay: 0 } as unknown as ComponentProps<typeof HoverCard>;\nconst ICON_VIEWBOX = 24;\nconst ICON_CENTER = 12;\nconst ICON_STROKE_WIDTH = 2;\n\ntype ModelId = string;\n\n/**\n * Flat token-usage shape this element renders. Intentionally decoupled from the\n * AI SDK's `LanguageModelUsage` — that type nests reasoning/cache counts under\n * `input`/`outputTokenDetails` and reshapes them between majors, while this\n * element only ever reads flat counts. Callers build this from whatever usage\n * metadata they have (server turn metadata, provider usage, etc.).\n */\nexport type ContextUsage = {\n  inputTokens?: number;\n  outputTokens?: number;\n  totalTokens?: number;\n  reasoningTokens?: number;\n  cachedInputTokens?: number;\n};\n\ninterface ContextSchema {\n  usedTokens: number;\n  maxTokens: number;\n  usage?: ContextUsage;\n  modelId?: ModelId;\n}\n\nconst ContextContext = createContext<ContextSchema | null>(null);\n\nconst useContextValue = () => {\n  const context = useContext(ContextContext);\n\n  if (!context) {\n    throw new Error(\"Context components must be used within Context\");\n  }\n\n  return context;\n};\n\nexport type ContextProps = ComponentProps<typeof HoverCard> & ContextSchema;\n\nexport const Context = ({\n  usedTokens,\n  maxTokens,\n  usage,\n  modelId,\n  ...props\n}: ContextProps) => {\n  const contextValue = useMemo(\n    () => ({ maxTokens, modelId, usage, usedTokens }),\n    [maxTokens, modelId, usage, usedTokens]\n  );\n\n  return (\n    <ContextContext.Provider value={contextValue}>\n      <HoverCard {...NO_DELAY} {...props} />\n    </ContextContext.Provider>\n  );\n};\n\nconst ContextIcon = () => {\n  const { usedTokens, maxTokens } = useContextValue();\n  const circumference = 2 * Math.PI * ICON_RADIUS;\n  const usedPercent = usedTokens / maxTokens;\n  const dashOffset = circumference * (1 - usedPercent);\n\n  return (\n    <svg\n      aria-label=\"Model context usage\"\n      height=\"20\"\n      role=\"img\"\n      style={{ color: \"currentcolor\" }}\n      viewBox={`0 0 ${ICON_VIEWBOX} ${ICON_VIEWBOX}`}\n      width=\"20\"\n    >\n      <circle\n        cx={ICON_CENTER}\n        cy={ICON_CENTER}\n        fill=\"none\"\n        opacity=\"0.25\"\n        r={ICON_RADIUS}\n        stroke=\"currentColor\"\n        strokeWidth={ICON_STROKE_WIDTH}\n      />\n      <circle\n        cx={ICON_CENTER}\n        cy={ICON_CENTER}\n        fill=\"none\"\n        opacity=\"0.7\"\n        r={ICON_RADIUS}\n        stroke=\"currentColor\"\n        strokeDasharray={`${circumference} ${circumference}`}\n        strokeDashoffset={dashOffset}\n        strokeLinecap=\"round\"\n        strokeWidth={ICON_STROKE_WIDTH}\n        style={{ transform: \"rotate(-90deg)\", transformOrigin: \"center\" }}\n      />\n    </svg>\n  );\n};\n\nexport type ContextTriggerProps = ComponentProps<typeof Button>;\n\nexport const ContextTrigger = ({ children, ...props }: ContextTriggerProps) => {\n  const { usedTokens, maxTokens } = useContextValue();\n  const usedPercent = usedTokens / maxTokens;\n  const renderedPercent = new Intl.NumberFormat(\"en-US\", {\n    maximumFractionDigits: 1,\n    style: \"percent\",\n  }).format(usedPercent);\n\n  return (\n    <HoverCardTrigger asChild>\n      {children ?? (\n        <Button type=\"button\" variant=\"ghost\" {...props}>\n          <span className=\"font-medium text-muted-foreground\">\n            {renderedPercent}\n          </span>\n          <ContextIcon />\n        </Button>\n      )}\n    </HoverCardTrigger>\n  );\n};\n\nexport type ContextContentProps = ComponentProps<typeof HoverCardContent>;\n\nexport const ContextContent = ({\n  className,\n  ...props\n}: ContextContentProps) => (\n  <HoverCardContent\n    className={cn(\"min-w-60 divide-y overflow-hidden p-0\", className)}\n    {...props}\n  />\n);\n\nexport type ContextContentHeaderProps = ComponentProps<\"div\">;\n\nexport const ContextContentHeader = ({\n  children,\n  className,\n  ...props\n}: ContextContentHeaderProps) => {\n  const { usedTokens, maxTokens } = useContextValue();\n  const usedPercent = usedTokens / maxTokens;\n  const displayPct = new Intl.NumberFormat(\"en-US\", {\n    maximumFractionDigits: 1,\n    style: \"percent\",\n  }).format(usedPercent);\n  const used = new Intl.NumberFormat(\"en-US\", {\n    notation: \"compact\",\n  }).format(usedTokens);\n  const total = new Intl.NumberFormat(\"en-US\", {\n    notation: \"compact\",\n  }).format(maxTokens);\n\n  return (\n    <div className={cn(\"w-full space-y-2 p-3\", className)} {...props}>\n      {children ?? (\n        <>\n          <div className=\"flex items-center justify-between gap-3 text-xs\">\n            <p>{displayPct}</p>\n            <p className=\"font-mono text-muted-foreground\">\n              {used} / {total}\n            </p>\n          </div>\n          <div className=\"space-y-2\">\n            <Progress className=\"bg-muted\" value={usedPercent * PERCENT_MAX} />\n          </div>\n        </>\n      )}\n    </div>\n  );\n};\n\nexport type ContextContentBodyProps = ComponentProps<\"div\">;\n\nexport const ContextContentBody = ({\n  children,\n  className,\n  ...props\n}: ContextContentBodyProps) => (\n  <div className={cn(\"w-full p-3\", className)} {...props}>\n    {children}\n  </div>\n);\n\nexport type ContextContentFooterProps = ComponentProps<\"div\">;\n\nexport const ContextContentFooter = ({\n  children,\n  className,\n  ...props\n}: ContextContentFooterProps) => {\n  const { modelId, usage } = useContextValue();\n  const costUSD = modelId\n    ? getUsage({\n        modelId,\n        usage: {\n          input: usage?.inputTokens ?? 0,\n          output: usage?.outputTokens ?? 0,\n        },\n      }).costUSD?.totalUSD\n    : undefined;\n  const totalCost = new Intl.NumberFormat(\"en-US\", {\n    currency: \"USD\",\n    style: \"currency\",\n  }).format(costUSD ?? 0);\n\n  return (\n    <div\n      className={cn(\n        \"flex w-full items-center justify-between gap-3 bg-secondary p-3 text-xs\",\n        className\n      )}\n      {...props}\n    >\n      {children ?? (\n        <>\n          <span className=\"text-muted-foreground\">Total cost</span>\n          <span>{totalCost}</span>\n        </>\n      )}\n    </div>\n  );\n};\n\nconst TokensWithCost = ({\n  tokens,\n  costText,\n}: {\n  tokens?: number;\n  costText?: string;\n}) => (\n  <span>\n    {tokens === undefined\n      ? \"—\"\n      : new Intl.NumberFormat(\"en-US\", {\n          notation: \"compact\",\n        }).format(tokens)}\n    {costText ? (\n      <span className=\"ml-2 text-muted-foreground\">• {costText}</span>\n    ) : null}\n  </span>\n);\n\nexport type ContextInputUsageProps = ComponentProps<\"div\">;\n\nexport const ContextInputUsage = ({\n  className,\n  children,\n  ...props\n}: ContextInputUsageProps) => {\n  const { usage, modelId } = useContextValue();\n  const inputTokens = usage?.inputTokens ?? 0;\n\n  if (children) {\n    return children;\n  }\n\n  if (!inputTokens) {\n    return null;\n  }\n\n  const inputCost = modelId\n    ? getUsage({\n        modelId,\n        usage: { input: inputTokens, output: 0 },\n      }).costUSD?.totalUSD\n    : undefined;\n  const inputCostText = new Intl.NumberFormat(\"en-US\", {\n    currency: \"USD\",\n    style: \"currency\",\n  }).format(inputCost ?? 0);\n\n  return (\n    <div\n      className={cn(\"flex items-center justify-between text-xs\", className)}\n      {...props}\n    >\n      <span className=\"text-muted-foreground\">Input</span>\n      <TokensWithCost costText={inputCostText} tokens={inputTokens} />\n    </div>\n  );\n};\n\nexport type ContextOutputUsageProps = ComponentProps<\"div\">;\n\nexport const ContextOutputUsage = ({\n  className,\n  children,\n  ...props\n}: ContextOutputUsageProps) => {\n  const { usage, modelId } = useContextValue();\n  const outputTokens = usage?.outputTokens ?? 0;\n\n  if (children) {\n    return children;\n  }\n\n  if (!outputTokens) {\n    return null;\n  }\n\n  const outputCost = modelId\n    ? getUsage({\n        modelId,\n        usage: { input: 0, output: outputTokens },\n      }).costUSD?.totalUSD\n    : undefined;\n  const outputCostText = new Intl.NumberFormat(\"en-US\", {\n    currency: \"USD\",\n    style: \"currency\",\n  }).format(outputCost ?? 0);\n\n  return (\n    <div\n      className={cn(\"flex items-center justify-between text-xs\", className)}\n      {...props}\n    >\n      <span className=\"text-muted-foreground\">Output</span>\n      <TokensWithCost costText={outputCostText} tokens={outputTokens} />\n    </div>\n  );\n};\n\nexport type ContextReasoningUsageProps = ComponentProps<\"div\">;\n\nexport const ContextReasoningUsage = ({\n  className,\n  children,\n  ...props\n}: ContextReasoningUsageProps) => {\n  const { usage, modelId } = useContextValue();\n  const reasoningTokens = usage?.reasoningTokens ?? 0;\n\n  if (children) {\n    return children;\n  }\n\n  if (!reasoningTokens) {\n    return null;\n  }\n\n  const reasoningCost = modelId\n    ? getUsage({\n        modelId,\n        usage: { reasoningTokens },\n      }).costUSD?.totalUSD\n    : undefined;\n  const reasoningCostText = new Intl.NumberFormat(\"en-US\", {\n    currency: \"USD\",\n    style: \"currency\",\n  }).format(reasoningCost ?? 0);\n\n  return (\n    <div\n      className={cn(\"flex items-center justify-between text-xs\", className)}\n      {...props}\n    >\n      <span className=\"text-muted-foreground\">Reasoning</span>\n      <TokensWithCost costText={reasoningCostText} tokens={reasoningTokens} />\n    </div>\n  );\n};\n\nexport type ContextCacheUsageProps = ComponentProps<\"div\">;\n\nexport const ContextCacheUsage = ({\n  className,\n  children,\n  ...props\n}: ContextCacheUsageProps) => {\n  const { usage, modelId } = useContextValue();\n  const cacheTokens = usage?.cachedInputTokens ?? 0;\n\n  if (children) {\n    return children;\n  }\n\n  if (!cacheTokens) {\n    return null;\n  }\n\n  const cacheCost = modelId\n    ? getUsage({\n        modelId,\n        usage: { cacheReads: cacheTokens, input: 0, output: 0 },\n      }).costUSD?.totalUSD\n    : undefined;\n  const cacheCostText = new Intl.NumberFormat(\"en-US\", {\n    currency: \"USD\",\n    style: \"currency\",\n  }).format(cacheCost ?? 0);\n\n  return (\n    <div\n      className={cn(\"flex items-center justify-between text-xs\", className)}\n      {...props}\n    >\n      <span className=\"text-muted-foreground\">Cache</span>\n      <TokensWithCost costText={cacheCostText} tokens={cacheTokens} />\n    </div>\n  );\n};\n",
      "type": "registry:component",
      "target": "components/ai-elements/context.tsx"
    }
  ],
  "type": "registry:component"
}