{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "meter",
  "title": "Meter",
  "description": "A brass metering instrument with a rolling reading: live spend that ticks up, or a prepaid balance that counts down.",
  "dependencies": [
    "@base-ui/react",
    "cn"
  ],
  "registryDependencies": [
    "https://bevel-ui.vercel.app/r/bevel.json",
    "https://bevel-ui.vercel.app/r/number-wheel.json"
  ],
  "files": [
    {
      "path": "registry/bevel/ui/meter.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Button as ButtonPrimitive } from \"@base-ui/react/button\"\nimport { mergeProps } from \"@base-ui/react/merge-props\"\nimport { useRender } from \"@base-ui/react/use-render\"\nimport { cn } from \"cn\"\nimport { NumberWheel, type NumberWheelProps } from \"@/components/ui/number-wheel\"\n\ntype MeterState = \"idle\" | \"running\" | \"stopped\"\n\nconst MeterContext = React.createContext<{ state: MeterState }>({ state: \"idle\" })\n\ntype MeterProps = useRender.ComponentProps<\"div\"> & {\n  /** running: the reading is ticking (taxi fare, live spend). stopped: it has settled. */\n  state?: MeterState\n  /** Bezel finish. */\n  variant?: \"brass\" | \"graphite\"\n}\n\n/**\n * A metering instrument: a bezel around a face with a rolling reading.\n * Use it for prepaid balances that count down or running totals that count up.\n */\nfunction Meter({ className, render, state = \"idle\", variant = \"brass\", children, ...props }: MeterProps) {\n  const context = React.useMemo(() => ({ state }), [state])\n  const element = useRender({\n    defaultTagName: \"div\",\n    render,\n    props: mergeProps<\"div\">(\n      {\n        role: \"group\",\n        \"data-slot\": \"meter\",\n        \"data-state\": state,\n        \"data-variant\": variant,\n        className: cn(\n          \"bevel-metal bevel-object relative w-full max-w-sm rounded-(--bevel-radius-lg) p-(--bevel-stitch-inset)\",\n          \"forced-colors:border forced-colors:border-[CanvasText]\",\n          className\n        ),\n        children: (\n          <div\n            data-slot=\"meter-face\"\n            className=\"bevel-leather flex flex-col gap-4 rounded-[calc(var(--bevel-radius-lg)-var(--bevel-stitch-inset))] p-5 text-(--meter-foreground) shadow-(--bevel-depth-recessed)\"\n          >\n            {children}\n          </div>\n        ),\n      } as React.ComponentProps<\"div\">,\n      props\n    ),\n  })\n  return <MeterContext value={context}>{element}</MeterContext>\n}\n\nfunction MeterHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"meter-header\"\n      className={cn(\"flex items-center justify-between gap-3\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction MeterLabel({ className, ...props }: React.ComponentProps<\"p\">) {\n  return (\n    <p\n      data-slot=\"meter-label\"\n      className={cn(\n        \"bevel-deboss text-(length:--bevel-label) font-semibold tracking-(--bevel-tracking-label) text-(--meter-muted-foreground) uppercase\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nconst flagText: Record<MeterState, string> = { idle: \"Ready\", running: \"Running\", stopped: \"Stopped\" }\n\n/** The meter's flag: a lamp that lights while the reading runs. Children replace the text. */\nfunction MeterFlag({ className, children, ...props }: React.ComponentProps<\"span\">) {\n  const { state } = React.useContext(MeterContext)\n  return (\n    <span\n      data-slot=\"meter-flag\"\n      className={cn(\n        \"bevel-deboss inline-flex items-center gap-1.5 text-(length:--bevel-label) font-medium text-(--meter-muted-foreground)\",\n        className\n      )}\n      {...props}\n    >\n      <span aria-hidden className=\"bevel-led size-2 shrink-0 rounded-full\" />\n      {children ?? flagText[state]}\n    </span>\n  )\n}\n\n/** The rolling reading. Announces its value to screen readers only once it stops running. */\nfunction MeterReading({ className, live, ...props }: NumberWheelProps) {\n  const { state } = React.useContext(MeterContext)\n  return (\n    <NumberWheel\n      data-meter-reading=\"\"\n      live={live ?? (state === \"running\" ? \"off\" : \"polite\")}\n      className={cn(\"self-start text-(length:--bevel-amount)\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction MeterUnit({ className, ...props }: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"meter-unit\"\n      className={cn(\"bevel-deboss text-sm text-(--meter-muted-foreground)\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction MeterFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return <div data-slot=\"meter-footer\" className={cn(\"flex items-center gap-2\", className)} {...props} />\n}\n\n/** A brass push-button on the meter. Sinks when pressed. */\nfunction MeterButton({ className, ...props }: ButtonPrimitive.Props) {\n  return (\n    <ButtonPrimitive\n      data-slot=\"meter-button\"\n      className={cn(\n        \"bevel-raised inline-flex h-9 flex-1 items-center justify-center gap-1.5 rounded-(--bevel-radius-sm) px-3 text-sm font-semibold text-(--bevel-ivory-foreground) outline-none select-none\",\n        \"transition-[translate,box-shadow] duration-(--bevel-duration-press) ease-(--bevel-ease-out) motion-reduce:transition-none\",\n        \"active:translate-y-0.5 active:bevel-pressed data-pressed:translate-y-0.5 data-pressed:bevel-pressed\",\n        \"focus-visible:ring-3 focus-visible:ring-(--meter-foreground)/40\",\n        \"data-disabled:cursor-not-allowed data-disabled:opacity-60\",\n        \"forced-colors:border forced-colors:border-[ButtonText]\",\n        \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { Meter, MeterHeader, MeterLabel, MeterFlag, MeterReading, MeterUnit, MeterFooter, MeterButton }\nexport type { MeterProps, MeterState }\n",
      "type": "registry:ui"
    }
  ],
  "css": {
    ":root": {
      "--meter-face": "oklch(0.24 0.012 260)",
      "--meter-foreground": "oklch(0.93 0.02 90)",
      "--meter-muted-foreground": "oklch(0.74 0.02 90)",
      "--meter-running": "oklch(0.82 0.17 75)",
      "--meter-stopped": "oklch(0.45 0.01 260)"
    },
    "[data-slot=\"meter\"]": {
      "--bevel-material": "var(--bevel-brass)",
      "--bevel-material-edge": "var(--bevel-brass-edge)",
      "--bevel-led": "var(--meter-stopped)"
    },
    "[data-slot=\"meter\"][data-variant=\"graphite\"]": {
      "--bevel-material": "oklch(0.42 0.01 260)",
      "--bevel-material-edge": "oklch(0.28 0.01 260)"
    },
    "[data-slot=\"meter\"][data-state=\"running\"]": {
      "--bevel-led": "var(--meter-running)"
    },
    "[data-slot=\"meter-face\"]": {
      "--bevel-material": "var(--meter-face)",
      "--bevel-material-recess": "oklch(0.17 0.01 260)"
    },
    "[data-slot=\"meter-button\"]": {
      "--bevel-material": "var(--bevel-brass)",
      "--bevel-material-edge": "var(--bevel-brass-edge)"
    }
  },
  "categories": [
    "money"
  ],
  "type": "registry:ui"
}