{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sources",
  "title": "Sources",
  "description": "what an answer is based on · numbered chips · `[n]` in text → inline citations · previews in a Sheet",
  "dependencies": [
    "lucide-react-native@^1.21.0"
  ],
  "registryDependencies": [
    "@kit-native/icon",
    "@kit-native/lib-utils",
    "@kit-native/sheet",
    "@kit-native/text"
  ],
  "files": [
    {
      "path": "components/kit/sources.tsx",
      "content": "import { Sheet } from '@/components/kit/sheet';\nimport { Icon } from '@/components/ui/icon';\nimport { Text } from '@/components/ui/text';\nimport { cn } from '@/lib/utils';\nimport { ExternalLinkIcon, FileTextIcon } from 'lucide-react-native';\nimport * as React from 'react';\nimport { Linking, Pressable, View } from 'react-native';\n\nexport type Source = {\n  title: string;\n  /** Where it lives: \"Invoice · 28 May\", \"help.northwind.co\". */\n  meta?: string;\n  /** The passage the answer used, one or two sentences. */\n  snippet?: string;\n  href?: string;\n};\n\n/** The nth source's preview in a bottom sheet (a phone has no room for a popover). */\nfunction PreviewSheet({ n, source, onClose }: { n: number; source?: Source; onClose: () => void }) {\n  return (\n    <Sheet open={!!source} onClose={onClose} title={source ? `Source ${n}` : undefined}>\n      {source ? (\n        <View className=\"gap-3 px-5 pb-2\">\n          <Text className=\"font-semibold\">{source.title}</Text>\n          {source.meta ? <Text className=\"text-muted-foreground text-xs\">{source.meta}</Text> : null}\n          {source.snippet ? (\n            <View className=\"border-border border-l-2 pl-3\">\n              <Text className=\"text-muted-foreground leading-6\">{source.snippet}</Text>\n            </View>\n          ) : null}\n          {source.href ? (\n            <Pressable onPress={() => Linking.openURL(source.href!)} accessibilityRole=\"link\" className=\"min-h-11 flex-row items-center gap-1 self-start\">\n              <Text className=\"text-sm font-medium underline\">Open source</Text>\n              <Icon as={ExternalLinkIcon} size={12} />\n            </Pressable>\n          ) : null}\n        </View>\n      ) : null}\n    </Sheet>\n  );\n}\n\nfunction usePreview(sources: Source[]) {\n  const [open, setOpen] = React.useState<number | null>(null);\n  const sheet = <PreviewSheet n={(open ?? 0) + 1} source={open === null ? undefined : sources[open]} onClose={() => setOpen(null)} />;\n  return { show: setOpen, sheet };\n}\n\n/** The sources under an answer: numbered chips, each opening a preview of what was used. */\nexport function SourceList({ sources, label = 'Sources', className }: { sources: Source[]; label?: string; className?: string }) {\n  const { show, sheet } = usePreview(sources);\n  if (!sources.length) return null;\n  return (\n    <View className={cn('gap-2', className)}>\n      <Text className=\"text-muted-foreground text-xs font-medium\">{label}</Text>\n      <View accessibilityLabel={label} className=\"flex-row flex-wrap gap-2\">\n        {sources.map((s, i) => (\n          <Pressable\n            key={`${s.title}-${i}`}\n            onPress={() => show(i)}\n            accessibilityRole=\"button\"\n            accessibilityLabel={`Source ${i + 1}: ${s.title}`}\n            className=\"border-border bg-card active:bg-accent min-h-9 max-w-60 flex-row items-center gap-2 rounded-lg border px-2 py-1\">\n            <View className=\"bg-muted size-4 items-center justify-center rounded\">\n              <Text className=\"text-[10px] font-medium leading-3\">{i + 1}</Text>\n            </View>\n            <Icon as={FileTextIcon} size={14} className=\"text-muted-foreground\" />\n            <Text numberOfLines={1} className=\"flex-shrink text-xs\">\n              {s.title}\n            </Text>\n          </Pressable>\n        ))}\n      </View>\n      {sheet}\n    </View>\n  );\n}\n\n/**\n * An answer with inline citations: every `[n]` in `text` becomes a small numbered marker that opens the\n * nth source's preview. While an answer streams, show it with `stripCitations` instead.\n */\nexport function CitedText({ text, sources, className }: { text: string; sources: Source[]; className?: string }) {\n  const { show, sheet } = usePreview(sources);\n  const parts = text.split(/(\\[\\d+\\])/g);\n  return (\n    <>\n      <Text className={className ?? 'leading-6'}>\n        {parts.map((part, i) => {\n          const n = /^\\[(\\d+)\\]$/.exec(part)?.[1];\n          const source = n ? sources[Number(n) - 1] : undefined;\n          if (!n || !source) return part;\n          return (\n            <Text key={i} onPress={() => show(Number(n) - 1)} accessibilityRole=\"button\" accessibilityLabel={`Source ${n}: ${source.title}`} className=\"bg-muted text-xs font-medium\">\n              {` ${n} `}\n            </Text>\n          );\n        })}\n      </Text>\n      {sheet}\n    </>\n  );\n}\n\n/** The answer without its `[n]` markers, for StreamingText. */\nexport const stripCitations = (text: string) => text.replace(/\\s?\\[\\d+\\]/g, '');\n",
      "type": "registry:component",
      "target": "components/kit/sources.tsx"
    }
  ],
  "meta": {
    "exports": [
      "SourceList",
      "CitedText",
      "stripCitations"
    ],
    "api": "<CitedText text=\"… [1]\" sources={[{ title, meta?, snippet?, href? }]} /><SourceList sources />"
  },
  "docs": "Run `npx expo install --fix` afterwards so Expo SDK packages match your SDK. Needs the kit theme (`@kit-native/theme`) and `KitThemeProvider` from `@kit-native/lib-theme-context` at the root.",
  "categories": [
    "ai"
  ],
  "type": "registry:component"
}