{"$schema":"https:\/\/ui.particle.academy\/schema\/registry-item.json","name":"reason-tag","type":"registry:ui","title":"ReasonTag","description":"ReasonTag from react-fancy","package":"react-fancy","dependencies":[],"registryDependencies":["popover","button"],"files":[{"path":"components\/fancy\/reason-tag\/ReasonTag.tsx","content":"import { Popover } from \"..\/Popover\";\r\nimport { Button } from \"..\/Button\";\r\n\r\n\/**\r\n * ReasonTag \u2014 wraps any value with a small affordance that reveals the\r\n * agent's reasoning, sources, and confidence on hover or click.\r\n *\r\n *   <ReasonTag\r\n *     value=\"$1.4M\"\r\n *     reason=\"Projected Q3 ARR after stacking renewals.\"\r\n *     confidence={0.91}\r\n *     sources={[{ label: \"Q2 actuals \u00b7 CRM export\" }]}\r\n *     by=\"Forecaster\"\r\n *   \/>\r\n *\r\n * Three visual styles:\r\n *   \u2022 \"dot\"       \u2014 value with a tiny coloured dot (default, subtle)\r\n *   \u2022 \"underline\" \u2014 dotted underline + trailing \"?\"\r\n *   \u2022 \"chip\"      \u2014 full coloured pill (loud)\r\n *\r\n * Confidence drives the colour via three tiers (high \/ medium \/ low),\r\n * so a quick visual scan tells the human which suggestions deserve a\r\n * second look without opening any tooltips.\r\n *\r\n * `pinned` swaps the popover for an inline annotation slot \u2014 useful\r\n * when explainability should always be visible, not buried in a hover.\r\n *\/\r\nexport type ReasonTagSource = { label: string; href?: string };\r\n\r\nexport type ReasonTagTheme = \"dot\" | \"underline\" | \"chip\";\r\n\r\nexport interface ReasonTagProps {\r\n  \/** The value the tag wraps \u2014 usually a number, label, or short phrase. *\/\r\n  value: React.ReactNode;\r\n  \/** Free-text rationale shown in the popover \/ inline annotation. *\/\r\n  reason: string;\r\n  \/** 0..1 confidence. Drives the tier colour. Defaults to 1. *\/\r\n  confidence?: number;\r\n  \/** Optional list of sources (label + optional href). *\/\r\n  sources?: ReasonTagSource[];\r\n  \/** Optional author \/ agent name shown in the popover header. *\/\r\n  by?: string;\r\n  \/** Visual treatment for the trigger. *\/\r\n  theme?: ReasonTagTheme;\r\n  \/**\r\n   * When true, the popover is replaced with an always-visible inline\r\n   * annotation below the value.\r\n   *\/\r\n  pinned?: boolean;\r\n  \/** Called when the user hits the \"ask follow-up\" action. *\/\r\n  onFollowUp?: () => void;\r\n  \/** Optional className applied to the trigger element. *\/\r\n  className?: string;\r\n}\r\n\r\nconst CONFIDENCE_TIERS: Array<{ min: number; color: string; label: string }> = [\r\n  { min: 0.85, color: \"#10b981\", label: \"high\" },\r\n  { min: 0.6, color: \"#f59e0b\", label: \"medium\" },\r\n  { min: 0, color: \"#ef4444\", label: \"low\" },\r\n];\r\n\r\nfunction tier(c: number) {\r\n  return CONFIDENCE_TIERS.find((t) => c >= t.min) ?? CONFIDENCE_TIERS[2];\r\n}\r\n\r\nexport function ReasonTag({\r\n  value,\r\n  reason,\r\n  confidence = 1,\r\n  sources = [],\r\n  by,\r\n  theme = \"dot\",\r\n  pinned = false,\r\n  onFollowUp,\r\n  className,\r\n}: ReasonTagProps) {\r\n  const t = tier(confidence);\r\n\r\n  const trigger =\r\n    theme === \"chip\" ? (\r\n      <span\r\n        className={`inline-flex cursor-help items-center gap-1 rounded-full px-2 py-0.5 text-[12px] font-medium ${className ?? \"\"}`}\r\n        style={{ backgroundColor: t.color + \"22\", color: t.color }}\r\n      >\r\n        <span\r\n          className=\"h-1.5 w-1.5 rounded-full\"\r\n          style={{ backgroundColor: t.color }}\r\n        \/>\r\n        {value}\r\n        <span className=\"text-[10px] opacity-70\">?<\/span>\r\n      <\/span>\r\n    ) : theme === \"underline\" ? (\r\n      <span\r\n        className={`cursor-help underline decoration-dotted underline-offset-2 ${className ?? \"\"}`}\r\n        style={{ textDecorationColor: t.color }}\r\n      >\r\n        {value}\r\n        <span\r\n          className=\"ml-0.5 font-mono text-[10px]\"\r\n          style={{ color: t.color }}\r\n        >\r\n          ?\r\n        <\/span>\r\n      <\/span>\r\n    ) : (\r\n      <span className={`inline-flex cursor-help items-baseline gap-1 ${className ?? \"\"}`}>\r\n        <span className=\"font-medium\">{value}<\/span>\r\n        <span\r\n          className=\"inline-block h-1.5 w-1.5 rounded-full align-middle\"\r\n          style={{ backgroundColor: t.color }}\r\n          title=\"reason available\"\r\n        \/>\r\n      <\/span>\r\n    );\r\n\r\n  if (pinned) {\r\n    return (\r\n      <span className=\"inline-flex flex-col items-start gap-0.5 align-top\">\r\n        {trigger}\r\n        <span\r\n          className=\"block max-w-[280px] rounded border-l-2 pl-2 text-[11px] leading-snug text-zinc-600 dark:text-zinc-300\"\r\n          style={{ borderColor: t.color }}\r\n        >\r\n          {reason}\r\n        <\/span>\r\n      <\/span>\r\n    );\r\n  }\r\n\r\n  return (\r\n    <Popover hover>\r\n      <Popover.Trigger>{trigger}<\/Popover.Trigger>\r\n      <Popover.Content>\r\n        <div className=\"w-72 space-y-2 text-sm\">\r\n          <div className=\"flex items-baseline gap-2\">\r\n            <span\r\n              className=\"text-[10px] font-semibold uppercase tracking-wider\"\r\n              style={{ color: t.color }}\r\n            >\r\n              {t.label} confidence \u00b7 {(confidence * 100).toFixed(0)}%\r\n            <\/span>\r\n            {by && (\r\n              <span className=\"ml-auto font-mono text-[10px] text-zinc-400\">\r\n                @{by}\r\n              <\/span>\r\n            )}\r\n          <\/div>\r\n          <p className=\"text-[13px] leading-snug text-zinc-700 dark:text-zinc-200\">\r\n            {reason}\r\n          <\/p>\r\n          {sources.length > 0 && (\r\n            <div>\r\n              <div className=\"text-[10px] uppercase tracking-wider text-zinc-400\">\r\n                sources\r\n              <\/div>\r\n              <ul className=\"mt-0.5 space-y-0.5 text-[12px]\">\r\n                {sources.map((s, i) => (\r\n                  <li key={i}>\r\n                    {s.href ? (\r\n                      <a className=\"text-violet-600 hover:underline\" href={s.href}>\r\n                        {s.label}\r\n                      <\/a>\r\n                    ) : (\r\n                      <span className=\"text-zinc-600 dark:text-zinc-300\">\r\n                        {s.label}\r\n                      <\/span>\r\n                    )}\r\n                  <\/li>\r\n                ))}\r\n              <\/ul>\r\n            <\/div>\r\n          )}\r\n          {onFollowUp && (\r\n            <div className=\"flex justify-end pt-1\">\r\n              <Button size=\"sm\" variant=\"ghost\" onClick={onFollowUp}>\r\n                ask follow-up\r\n              <\/Button>\r\n            <\/div>\r\n          )}\r\n        <\/div>\r\n      <\/Popover.Content>\r\n    <\/Popover>\r\n  );\r\n}\r\n","type":"registry:ui","target":"components\/fancy\/reason-tag\/ReasonTag.tsx"},{"path":"components\/fancy\/reason-tag\/index.ts","content":"export { ReasonTag } from \".\/ReasonTag\";\r\nexport type { ReasonTagProps, ReasonTagSource, ReasonTagTheme } from \".\/ReasonTag\";\r\n","type":"registry:ui","target":"components\/fancy\/reason-tag\/index.ts"}]}