{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "stat",
  "type": "registry:component",
  "title": "Stat",
  "description": "One figure written large, with a label over it, a unit after it and a badge beside it.",
  "dependencies": [
    "@base-ui/react",
    "tailwind-variants"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "components/panelui/stat.tsx",
      "type": "registry:component",
      "target": "@components/panelui/stat.tsx",
      "content": "'use client';\n\n/**\n * Stat — one figure written large, with what it is and what it means.\n *\n * ```tsx\n * <Stat>\n *   <Stat.Content>\n *     <Stat.Label>Response time</Stat.Label>\n *     <Stat.Value>\n *       240<Stat.Unit>ms</Stat.Unit>\n *     </Stat.Value>\n *   </Stat.Content>\n *   <Stat.Badge>60 ms inside budget</Stat.Badge>\n * </Stat>\n * ```\n *\n * ## The figure over the chart\n *\n * It is the reading at the top of a panel whose body is a meter, a bar chart\n * or a grid of days: the label says what is measured, the value is the\n * reading, and the badge on the trailing side says how that reading stands.\n * Change the value as the chart beside it changes and the two read as one.\n *\n * ## The row sets the baseline\n *\n * Inside `Stat`, the value is set solid, with no leading, so its foot sits on\n * the same line as the badge's at the bottom of the row. Outside it, as a\n * label and a value stacked on their own, the value keeps its line height and\n * sits in running text like any other line.\n *\n * ## The unit follows the value's size\n *\n * `Stat.Unit` is written inside `Stat.Value` and takes its size and its gap\n * from it, so a unit never has to be sized by hand to match its number.\n *\n * ## It renders on the server\n *\n * No state and no handlers. Everything that depends on where a part sits is\n * done in CSS from data attributes, so a Server Component can render it.\n */\nimport type { ComponentProps } from 'react';\nimport { tv } from 'tailwind-variants';\nimport { mergeProps } from '@base-ui/react/merge-props';\nimport { useRender } from '@base-ui/react/use-render';\nimport type { ElementType as RenderElementType } from 'react';\n\n/** Draws a part as another element, or composes it with a component: `render={<a href=\"/\" />}`. */\ntype RenderProp<Tag extends RenderElementType> = { render?: useRender.ComponentProps<Tag>['render'] };\n\nconst statVariants = tv({\n  slots: {\n    root: 'flex items-end justify-between gap-4',\n    content: 'flex flex-col gap-1',\n    label: 'text-sm text-muted-foreground',\n    description: 'text-sm font-medium',\n    // Solid inside a row, so its foot lines up with the badge's.\n    value: 'group/stat-value font-bold tracking-tight in-data-[slot=stat]:leading-none',\n    unit: [\n      'ms-1 text-sm font-medium text-muted-foreground',\n      'group-data-[size=lg]/stat-value:ms-1.5 group-data-[size=lg]/stat-value:text-base',\n    ],\n    badge: 'rounded-full bg-muted px-2.5 py-1 text-xs font-medium text-muted-foreground',\n  },\n  variants: {\n    size: {\n      sm: { value: 'text-2xl' },\n      md: { value: 'text-3xl' },\n      lg: { value: 'text-4xl' },\n    },\n    weight: {\n      normal: {},\n      medium: { label: 'font-medium' },\n    },\n  },\n});\n\nexport interface StatProps extends ComponentProps<'div'> {}\n\n/** A row: the label and value on the leading side, a badge on the trailing one. */\nfunction StatRoot({ className, render, ...props }: StatProps & RenderProp<'div'>) {\n  return useRender({\n    defaultTagName: 'div',\n    render,\n    props: mergeProps({ 'data-slot': 'stat', className: statVariants().root({ className }) }, props),\n  });\n}\nStatRoot.displayName = 'Stat';\n\nexport interface StatContentProps extends ComponentProps<'div'> {}\n\n/** The label and the value, stacked. Used on its own when there is no badge. */\nfunction StatContent({ className, render, ...props }: StatContentProps & RenderProp<'div'>) {\n  return useRender({\n    defaultTagName: 'div',\n    render,\n    props: mergeProps({ 'data-slot': 'stat-content', className: statVariants().content({ className }) }, props),\n  });\n}\nStatContent.displayName = 'Stat.Content';\n\nexport interface StatLabelProps extends ComponentProps<'p'> {\n  /**\n   * `medium` sets the label in a heavier weight, for a figure that stands on\n   * its own rather than at the top of a panel that is already titled.\n   * Default `normal`.\n   */\n  weight?: 'normal' | 'medium';\n}\n\n/** What is measured, in a quiet line over the value. */\nfunction StatLabel({ weight = 'normal', className, render, ...props }: StatLabelProps & RenderProp<'p'>) {\n  return useRender({\n    defaultTagName: 'p',\n    render,\n    props: mergeProps({ 'data-slot': 'stat-label', className: statVariants({ weight }).label({ className }) }, props),\n  });\n}\nStatLabel.displayName = 'Stat.Label';\n\nexport interface StatDescriptionProps extends ComponentProps<'p'> {}\n\n/** What the reading means, in words: \"Answering slowly\". Written under the label. */\nfunction StatDescription({ className, render, ...props }: StatDescriptionProps & RenderProp<'p'>) {\n  return useRender({\n    defaultTagName: 'p',\n    render,\n    props: mergeProps({ 'data-slot': 'stat-description', className: statVariants().description({ className }) }, props),\n  });\n}\nStatDescription.displayName = 'Stat.Description';\n\nexport interface StatValueProps extends ComponentProps<'p'> {\n  /** `sm` is 2xl, `md` 3xl and `lg` 4xl. Default `lg`. */\n  size?: 'sm' | 'md' | 'lg';\n}\n\n/** The figure. Put a `Stat.Unit` inside it, after the number. */\nfunction StatValue({ size = 'lg', className, render, ...props }: StatValueProps & RenderProp<'p'>) {\n  return useRender({\n    defaultTagName: 'p',\n    render,\n    props: mergeProps(\n      { 'data-slot': 'stat-value', 'data-size': size, className: statVariants({ size }).value({ className }) },\n      props\n    ),\n  });\n}\nStatValue.displayName = 'Stat.Value';\n\nexport interface StatUnitProps extends ComponentProps<'span'> {}\n\n/** The unit after the number, smaller and quieter, sized from the value it is in. */\nfunction StatUnit({ className, render, ...props }: StatUnitProps & RenderProp<'span'>) {\n  return useRender({\n    defaultTagName: 'span',\n    render,\n    props: mergeProps({ 'data-slot': 'stat-unit', className: statVariants().unit({ className }) }, props),\n  });\n}\nStatUnit.displayName = 'Stat.Unit';\n\nexport interface StatBadgeProps extends ComponentProps<'span'> {}\n\n/** How the reading stands, in a pill on the row's trailing side. */\nfunction StatBadge({ className, render, ...props }: StatBadgeProps & RenderProp<'span'>) {\n  return useRender({\n    defaultTagName: 'span',\n    render,\n    props: mergeProps({ 'data-slot': 'stat-badge', className: statVariants().badge({ className }) }, props),\n  });\n}\nStatBadge.displayName = 'Stat.Badge';\n\nexport const Stat = Object.assign(StatRoot, {\n  Content: StatContent,\n  Label: StatLabel,\n  Description: StatDescription,\n  Value: StatValue,\n  Unit: StatUnit,\n  Badge: StatBadge,\n});\n\nexport { StatContent, StatLabel, StatDescription, StatValue, StatUnit, StatBadge };\n"
    }
  ]
}
