{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "callout",
  "type": "registry:ui",
  "title": "Callout",
  "description": "Inline-prose annotation. The \"stop and read this\" surface that punctuates long-form content (docs, MDX, READMEs). Distinct from `Alert` — Alert is an out-of-band runtime banner (\"your save failed\"), Callout is an in-band authored aside (\"note: this rule is…",
  "author": "ofri-peretz <https://github.com/ofri-peretz>",
  "categories": [
    "blog",
    "primitive"
  ],
  "dependencies": [
    "class-variance-authority",
    "lucide-react"
  ],
  "registryDependencies": [
    "https://ds.interlace.tools/r/theme.json",
    "https://ds.interlace.tools/r/cn.json",
    "https://ds.interlace.tools/r/typography.json"
  ],
  "files": [
    {
      "path": "registry/interlace-ui/callout.tsx",
      "target": "components/ui/callout.tsx",
      "type": "registry:ui",
      "content": "import * as React from 'react';\n\n// @interlace/callout v1.0.0 — Interlace design system.\n// Docs, props and live preview: https://ds.interlace.tools/c/callout\n// What changed since: https://ds.interlace.tools/c/callout#history\n// Generated banner — keep it, the upgrade diff reads this version.\n\n/**\n * @interlace/ui — Callout\n *\n * Inline-prose annotation. The \"stop and read this\" surface that punctuates\n * long-form content (docs, MDX, READMEs). Distinct from `Alert` — Alert is\n * an out-of-band runtime banner (\"your save failed\"), Callout is an in-band\n * authored aside (\"note: this rule is type-aware\"). Both can share pigment\n * but they live at different altitudes in the system.\n *\n * Five tones, each fixed to a lucide icon + a semantic-token border-tint:\n *\n *   - info     Info             — neutral context, parallel to the body\n *   - note     Lightbulb        — author tip / suggestion\n *   - success  CircleCheck      — confirmation / positive outcome\n *   - warn     TriangleAlert    — non-blocking caution\n *   - danger   OctagonAlert     — destructive / blocking consequence\n *\n * ## Anatomy\n *\n *   Callout                            (div — role=\"note\" — data-min-viewport=320)\n *     ├─ {icon}                        (lucide, decorative — aria-hidden)\n *     └─ <div>                         (text column)\n *         ├─ {title?}                  (Typography variant=ui font-medium)\n *         └─ {children}                (free-form prose)\n *\n * ## MIN_VIEWPORT — 320\n *\n * Callouts live inside body prose; they MUST work on the narrowest reading\n * viewport (320 CSS-px). The icon-left + text-column flex layout reflows\n * naturally — no horizontal scroll, no truncation.\n *\n * | Rule | Concept                          | Where in this file                                          |\n * | ---- | -------------------------------- | ----------------------------------------------------------- |\n * | R4   | Extends native el + VariantProps | `React.ComponentProps<'div'> & VariantProps<...>` + props   |\n * | R6   | data-slot on root                | `data-slot=\"callout\"` + data-tone                           |\n * | R7   | className merged + ...rest + ref | `cn(calloutVariants(...), className)` + `{...props}`        |\n * | R8   | No `isXxx`; enum for tone        | `tone` is a 5-way enum, never a boolean                     |\n * | R10  | Composition seam                 | `title` slot + `children`                                   |\n * | R14  | Declares min viewport            | `data-min-viewport={String(MIN_VIEWPORT)}` + exported const |\n * | R18  | Tailwind only                    | zero inline `style`; cva classes + Lucide via className     |\n * | R19  | Tokens only                      | `p-md` / `rounded-md` / `border-l-*` widths via spacing + radius tokens; colors via semantic tokens |\n * | R20  | AA contrast                      | tones map to AA-cleared semantic tokens (primary/destructive/foreground/muted-foreground) + neutral surface |\n * | R25  | Server component                 | no hooks → no `'use client'`                                |\n * | R26  | A11y from native el              | `role=\"note\"` on the div; lucide icon marked `aria-hidden`  |\n */\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport {\n  CircleCheck,\n  Info,\n  Lightbulb,\n  OctagonAlert,\n  TriangleAlert,\n} from 'lucide-react';\n\nimport { cn } from '@/lib/utils';\nimport { Typography } from '@/components/ui/typography';\n\n/**\n * Minimum viable viewport (CSS px) for this primitive. Below it, preflight\n * draws a dev-mode outline; in prod the component still renders. Exported\n * so consumers / tests can read it.\n */\nexport const MIN_VIEWPORT = 320 as const;\n\nconst calloutVariants = cva(\n  // Base — flex row, icon left, text column right; 4px left border via\n  // `border-l-4`; padding from the spacing scale; rounded-md from radius\n  // tokens. Card-tint surface so the callout reads as a block in prose.\n  [\n    'flex items-start gap-sm',\n    'rounded-md border border-border border-l-4 bg-card/40 p-md',\n    '[&_[data-slot=callout-icon]]:size-5 [&_[data-slot=callout-icon]]:shrink-0',\n  ].join(' '),\n  {\n    variants: {\n      /**\n       * Narrative tone. Drives the icon, the left-border color, and the\n       * icon tint. Surface stays neutral so adjacent callouts don't fight\n       * each other for attention.\n       */\n      tone: {\n        info:\n          'border-l-primary [&_[data-slot=callout-icon]]:text-primary',\n        note:\n          'border-l-accent-foreground [&_[data-slot=callout-icon]]:text-accent-foreground',\n        success:\n          'border-l-primary [&_[data-slot=callout-icon]]:text-primary',\n        warn:\n          'border-l-foreground [&_[data-slot=callout-icon]]:text-foreground',\n        danger:\n          'border-l-destructive [&_[data-slot=callout-icon]]:text-destructive',\n      },\n    },\n    defaultVariants: {\n      tone: 'info',\n    },\n  },\n);\n\ntype CalloutTone = NonNullable<VariantProps<typeof calloutVariants>['tone']>;\n\n/** Per-tone lucide icon. One source of truth; no consumer override. */\nconst TONE_ICON: Record<CalloutTone, React.ComponentType<{ className?: string; 'aria-hidden'?: boolean }>> = {\n  info: Info,\n  note: Lightbulb,\n  success: CircleCheck,\n  warn: TriangleAlert,\n  danger: OctagonAlert,\n};\n\ninterface CalloutProps\n  extends Omit<React.ComponentProps<'div'>, 'title'>,\n    VariantProps<typeof calloutVariants> {\n  /**\n   * Optional headline above the body. Renders as Typography variant=ui\n   * font-medium. Note: overrides the native `<div title>` tooltip attribute\n   * with a React node — the native tooltip is rarely useful on a Callout\n   * and the visible heading wins.\n   */\n  title?: React.ReactNode;\n  children?: React.ReactNode;\n}\n\n/**\n * Inline-prose annotation. Server component (no hooks).\n *\n * Usage:\n *\n *   <Callout tone=\"warn\" title=\"Heads up\">\n *     This rule is type-aware and adds ~50ms to lint runs.\n *   </Callout>\n */\nconst Callout = React.forwardRef<HTMLDivElement, CalloutProps>(\n  ({ className, tone, title, children, ...props }, ref) => {\n    const resolvedTone: CalloutTone = tone ?? 'info';\n    const Icon = TONE_ICON[resolvedTone];\n\n    return (\n      <div\n        ref={ref}\n        role=\"note\"\n        data-slot=\"callout\"\n        data-min-viewport={String(MIN_VIEWPORT)}\n        data-tone={resolvedTone}\n        className={cn(calloutVariants({ tone }), className)}\n        {...props}\n      >\n        <Icon data-slot=\"callout-icon\" aria-hidden />\n        <div data-slot=\"callout-body\" className=\"min-w-0 flex-1\">\n          {title ? (\n            <Typography\n              as=\"p\"\n              variant=\"ui\"\n              className=\"font-medium\"\n              data-slot=\"callout-title\"\n            >\n              {title}\n            </Typography>\n          ) : null}\n          {children}\n        </div>\n      </div>\n    );\n  },\n);\nCallout.displayName = 'Callout';\n\nexport { Callout, calloutVariants };\nexport type { CalloutProps, CalloutTone };\n"
    }
  ],
  "meta": {
    "tier": "primitive",
    "client": false,
    "minViewport": 320,
    "loading": false,
    "version": "1.0.0",
    "since": "1.0.0"
  },
  "docs": "## @interlace/callout\n\nInstalled to `components/ui/callout.tsx`.\n\n```tsx\nimport { /* … */ } from '@/components/ui/callout';\n```\n\nProps, a11y contract, live preview and source: https://ds.interlace.tools/c/callout\n\nRequires the `@interlace/theme` CSS baseline (installed automatically as a registry dependency)."
}
