{"$schema":"https://ui.shadcn.com/schema/registry-item.json","author":"Eduardo Calvo <edu@smoothui.dev>","css":{},"dependencies":["motion"],"description":"Compact Badge and Status Dot for SmoothUI — labels, tags, and presence indicators.","devDependencies":[],"files":[{"content":"\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { motion, useReducedMotion } from \"motion/react\";\nimport { type ComponentProps, type ReactNode, useRef } from \"react\";\nimport {\n  EASE_OUT,\n  LOOP_CLASS,\n  LOOP_REPEAT_DELAY,\n  loopTransition,\n  useLoopInView,\n} from \"@/components/smoothui/lib/animation\";\n\nexport type BadgeVariant =\n  | \"default\"\n  | \"secondary\"\n  | \"outline\"\n  | \"destructive\"\n  | \"success\"\n  | \"warning\";\n\nexport type BadgeSize = \"sm\" | \"md\";\n\nexport interface BadgeProps extends Omit<ComponentProps<\"span\">, \"children\"> {\n  /** Optional leading icon or indicator */\n  children?: ReactNode;\n  /** Visual size */\n  size?: BadgeSize;\n  /** Color / emphasis treatment */\n  variant?: BadgeVariant;\n}\n\nexport type StatusDotStatus = \"online\" | \"offline\" | \"busy\" | \"away\";\n\nexport type StatusDotSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface StatusDotProps {\n  /** Optional CSS class names */\n  className?: string;\n  /** Pulse animation for live presence (honors reduced motion) */\n  pulse?: boolean;\n  /** Dot diameter */\n  size?: StatusDotSize;\n  /** Presence / health state */\n  status?: StatusDotStatus;\n}\n\nconst BADGE_VARIANT: Record<BadgeVariant, string> = {\n  default: \"border-transparent bg-primary text-primary-foreground\",\n  destructive:\n    \"border-transparent bg-destructive text-destructive-fg dark:bg-destructive/80\",\n  outline: \"border-foreground/25 bg-transparent text-foreground\",\n  secondary: \"border-transparent bg-secondary text-secondary-foreground\",\n  success:\n    \"border-transparent bg-emerald-500/15 text-emerald-700 dark:text-emerald-400\",\n  warning:\n    \"border-transparent bg-amber-500/15 text-amber-800 dark:text-amber-400\",\n};\n\nconst BADGE_SIZE: Record<BadgeSize, string> = {\n  md: \"h-5 gap-1 px-2 text-xs\",\n  sm: \"h-4 gap-0.5 px-1.5 text-[10px]\",\n};\n\nconst DOT_SIZE: Record<StatusDotSize, string> = {\n  lg: \"size-3\",\n  md: \"size-2.5\",\n  sm: \"size-2\",\n};\n\nconst DOT_COLOR: Record<StatusDotStatus, string> = {\n  away: \"bg-warning\",\n  busy: \"bg-destructive\",\n  offline: \"bg-smooth-600\",\n  online: \"bg-success\",\n};\n\n/**\n * SmoothUI Badge — compact label / tag. SmoothUI-owned (no Base/Radix twin).\n */\nexport default function Badge({\n  children,\n  className,\n  size = \"md\",\n  variant = \"default\",\n  ...props\n}: BadgeProps) {\n  return (\n    <span\n      className={cn(\n        \"ease inline-flex w-fit shrink-0 items-center justify-center whitespace-nowrap rounded-full border font-medium transition-colors duration-200 [&_svg]:pointer-events-none [&_svg]:size-3\",\n        BADGE_SIZE[size],\n        BADGE_VARIANT[variant],\n        className\n      )}\n      data-slot=\"badge\"\n      data-variant={variant}\n      {...props}\n    >\n      {children}\n    </span>\n  );\n}\n\n/**\n * Presence / health indicator. Place near avatars or list rows.\n */\nexport const StatusDot = ({\n  className,\n  pulse = false,\n  size = \"md\",\n  status = \"online\",\n}: StatusDotProps) => {\n  const shouldReduceMotion = useReducedMotion();\n  const hostRef = useRef<HTMLSpanElement>(null);\n  const inView = useLoopInView(hostRef);\n  const showPulse =\n    pulse && !shouldReduceMotion && status === \"online\" && inView;\n\n  return (\n    <span\n      aria-label={status}\n      className={cn(\n        \"relative inline-flex shrink-0 rounded-full\",\n        DOT_SIZE[size],\n        DOT_COLOR[status],\n        className\n      )}\n      data-slot=\"status-dot\"\n      data-status={status}\n      ref={hostRef}\n      role=\"status\"\n    >\n      {showPulse ? (\n        <motion.span\n          animate={{ opacity: [0.55, 0], scale: [1, 1.85] }}\n          aria-hidden\n          className={cn(\n            \"absolute inset-0 rounded-full\",\n            DOT_COLOR[status],\n            LOOP_CLASS\n          )}\n          transition={loopTransition(\n            { duration: 1.4, ease: EASE_OUT },\n            LOOP_REPEAT_DELAY.pulse\n          )}\n        />\n      ) : null}\n    </span>\n  );\n};\n","path":"index.tsx","target":"components/smoothui/badge/index.tsx","type":"registry:ui"}],"name":"badge","registryDependencies":["https://smoothui.dev/r/lib.json","https://smoothui.dev/r/tokens.json"],"title":"Badge","type":"registry:ui"}