{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "meter",
  "title": "Meter",
  "description": "A bar or an icon-sized ring for a measurement against a limit, like usage against a quota.",
  "dependencies": [
    "@base-ui/react",
    "@stylexjs/stylex"
  ],
  "registryDependencies": [
    "https://constella.aayush.cv/r/base.json"
  ],
  "files": [
    {
      "path": "src/components/primitives/meter.tsx",
      "content": "\"use client\";\n\nimport { Meter as MeterPrimitive } from \"@base-ui/react/meter\";\nimport * as stylex from \"@stylexjs/stylex\";\n\nimport type { Sx } from \"@/lib/constella/styles\";\nimport { trackStyles, typeStyles } from \"@/lib/constella/styles\";\nimport {\n  colors,\n  durations,\n  easings,\n  media,\n  sizes,\n  space,\n} from \"@/lib/constella/tokens.stylex\";\n\nconst meterColors = [\"success\", \"info\", \"warning\", \"danger\"] as const;\nconst meterVariants = [\"bar\", \"ring\"] as const;\n\ntype MeterColor = (typeof meterColors)[number];\ntype MeterVariant = (typeof meterVariants)[number];\n\ntype Styled<T> = Omit<T, \"className\" | \"style\"> & {\n  sx?: Sx;\n};\n\ntype MeterProps = Styled<MeterPrimitive.Root.Props> & {\n  color?: MeterColor;\n  variant?: MeterVariant;\n};\n\nconst styles = stylex.create({\n  success: {\n    backgroundColor: colors.successSolid,\n  },\n  info: {\n    backgroundColor: colors.infoSolid,\n  },\n  warning: {\n    backgroundColor: colors.warningSolid,\n  },\n  danger: {\n    backgroundColor: colors.dangerSolid,\n  },\n  ringRoot: {\n    alignItems: \"center\",\n    display: \"inline-flex\",\n    gap: space.xs,\n  },\n  // A step smaller than an icon, centered in an icon's box, as Spinner is, so the two swap in place.\n  ring: {\n    display: \"block\",\n    flexShrink: 0,\n    height: sizes.iconSm,\n    marginBlock: `calc((${sizes.icon} - ${sizes.iconSm}) / 2)`,\n    marginInline: `calc((${sizes.icon} - ${sizes.iconSm}) / 2)`,\n    // Starts at twelve o'clock and fills clockwise.\n    transform: \"rotate(-90deg)\",\n    width: sizes.iconSm,\n  },\n  ringTrack: {\n    fill: \"none\",\n    stroke: colors.fillOpaque,\n  },\n  ringIndicator: {\n    fill: \"none\",\n    stroke: colors.accentSolid,\n    strokeLinecap: \"round\",\n    transitionDuration: {\n      default: durations.move,\n      [media.reducedMotion]: \"0s\",\n    },\n    transitionProperty: \"stroke-dasharray, stroke\",\n    transitionTimingFunction: easings.out,\n  },\n  // A round cap on an empty ring would still draw a dot.\n  ringEmpty: {\n    strokeLinecap: \"butt\",\n  },\n  ringFill: (percent: number) => ({\n    strokeDasharray: `${percent} 100`,\n  }),\n  successRing: {\n    stroke: colors.successSolid,\n  },\n  infoRing: {\n    stroke: colors.infoSolid,\n  },\n  warningRing: {\n    stroke: colors.warningSolid,\n  },\n  dangerRing: {\n    stroke: colors.dangerSolid,\n  },\n});\n\nconst colorStyles = {\n  danger: styles.danger,\n  info: styles.info,\n  success: styles.success,\n  warning: styles.warning,\n} satisfies Record<MeterColor, stylex.StyleXStyles>;\n\nconst ringColorStyles = {\n  danger: styles.dangerRing,\n  info: styles.infoRing,\n  success: styles.successRing,\n  warning: styles.warningRing,\n} satisfies Record<MeterColor, stylex.StyleXStyles>;\n\nconst rootStyles = {\n  bar: trackStyles.root,\n  ring: styles.ringRoot,\n} satisfies Record<MeterVariant, stylex.StyleXStyles>;\n\nconst percentOf = (value: number, min: number, max: number) =>\n  max > min\n    ? Math.min(Math.max(((value - min) / (max - min)) * 100, 0), 100)\n    : 100;\n\n/**\n * Renders its fill after its children, so a label and value sit beside it: a bar under them,\n * or at `ring`, an icon-sized ring before them.\n */\nfunction Meter({\n  children,\n  color,\n  max = 100,\n  min = 0,\n  sx,\n  value,\n  variant = \"bar\",\n  ...props\n}: MeterProps) {\n  const percent = percentOf(value, min, max);\n  return (\n    <MeterPrimitive.Root\n      data-color={color}\n      data-slot=\"meter\"\n      data-variant={variant}\n      max={max}\n      min={min}\n      value={value}\n      {...props}\n      {...stylex.props(rootStyles[variant], sx)}\n    >\n      {variant === \"ring\" ? (\n        <svg\n          aria-hidden\n          data-slot=\"meter-ring\"\n          viewBox=\"0 0 16 16\"\n          {...stylex.props(styles.ring)}\n        >\n          <circle\n            cx={8}\n            cy={8}\n            pathLength={100}\n            r={6.5}\n            strokeWidth={3}\n            {...stylex.props(styles.ringTrack)}\n          />\n          <circle\n            cx={8}\n            cy={8}\n            pathLength={100}\n            r={6.5}\n            strokeWidth={3}\n            {...stylex.props(\n              styles.ringIndicator,\n              styles.ringFill(percent),\n              percent === 0 && styles.ringEmpty,\n              color && ringColorStyles[color]\n            )}\n          />\n        </svg>\n      ) : null}\n      {children}\n      {variant === \"bar\" ? (\n        <MeterTrack>\n          <MeterIndicator sx={color && colorStyles[color]} />\n        </MeterTrack>\n      ) : null}\n    </MeterPrimitive.Root>\n  );\n}\n\nfunction MeterTrack({ sx, ...props }: Styled<MeterPrimitive.Track.Props>) {\n  return (\n    <MeterPrimitive.Track\n      data-slot=\"meter-track\"\n      {...props}\n      {...stylex.props(trackStyles.track, sx)}\n    />\n  );\n}\n\nfunction MeterIndicator({\n  sx,\n  ...props\n}: Styled<MeterPrimitive.Indicator.Props>) {\n  return (\n    <MeterPrimitive.Indicator\n      data-slot=\"meter-indicator\"\n      {...props}\n      {...stylex.props(trackStyles.indicator, sx)}\n    />\n  );\n}\n\nfunction MeterLabel({ sx, ...props }: Styled<MeterPrimitive.Label.Props>) {\n  return (\n    <MeterPrimitive.Label\n      data-slot=\"meter-label\"\n      {...props}\n      {...stylex.props([typeStyles.textSm, trackStyles.label], sx)}\n    />\n  );\n}\n\nfunction MeterValue({ sx, ...props }: Styled<MeterPrimitive.Value.Props>) {\n  return (\n    <MeterPrimitive.Value\n      data-slot=\"meter-value\"\n      {...props}\n      {...stylex.props([typeStyles.textSm, trackStyles.value], sx)}\n    />\n  );\n}\n\nexport {\n  Meter,\n  MeterIndicator,\n  MeterLabel,\n  meterColors,\n  MeterTrack,\n  MeterValue,\n  meterVariants,\n};\nexport type { MeterColor, MeterProps, MeterVariant };\n",
      "type": "registry:component"
    }
  ],
  "docs": "Usage: https://constella.aayush.cv/docs/components/meter/index.md",
  "type": "registry:ui"
}