{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "research-session",
  "title": "Research Session",
  "description": "A research plan, live search activity, sources, and a cited synthesis.",
  "dependencies": [],
  "registryDependencies": [
    "https://uaiblocks.dev/r/uai-theme.json",
    "https://uaiblocks.dev/r/uai-utils.json",
    "https://uaiblocks.dev/r/citation.json",
    "https://uaiblocks.dev/r/progress-summary.json",
    "https://uaiblocks.dev/r/response-status.json",
    "https://uaiblocks.dev/r/task-list.json",
    "https://uaiblocks.dev/r/thinking.json"
  ],
  "files": [
    {
      "path": "src/registry/uai/blocks/research-session.tsx",
      "content": "\"use client\";\n\nimport { type ComponentProps, createContext, useContext, useId } from \"react\";\nimport { Citation, type CitationProps, type CitationVariant } from \"@/components/ui/uai/citation\";\nimport {\n  ProgressSummary,\n  type ProgressSummaryProps,\n  type ProgressSummaryVariant,\n} from \"@/components/ui/uai/progress-summary\";\nimport {\n  ResponseStatus,\n  type ResponseStatusProps,\n  type ResponseStatusVariant,\n} from \"@/components/ui/uai/response-status\";\nimport { TaskList, type TaskListProps, type TaskListVariant } from \"@/components/ui/uai/task-list\";\nimport { Thinking, type ThinkingProps } from \"@/components/ui/uai/thinking\";\nimport { cn } from \"@/lib/uai-utils\";\n\nexport const RESEARCH_SESSION_VARIANTS = [\"split\", \"stacked\", \"compact\"] as const;\nexport type ResearchSessionVariant = (typeof RESEARCH_SESSION_VARIANTS)[number];\nexport type ResearchSessionProps = ComponentProps<\"section\"> & {\n  variant?: ResearchSessionVariant;\n};\n\ntype SessionContext = { id: string; variant: ResearchSessionVariant };\nconst Context = createContext<SessionContext | null>(null);\nfunction useSession(part: string) {\n  const context = useContext(Context);\n  if (!context) throw new Error(`${part} must be used within ResearchSession`);\n  return context;\n}\nconst PanelContext = createContext<string | null>(null);\n\nconst progressVariants: Record<ResearchSessionVariant, ProgressSummaryVariant> = {\n  split: \"card\",\n  stacked: \"card\",\n  compact: \"compact\",\n};\nconst taskVariants: Record<ResearchSessionVariant, TaskListVariant> = {\n  split: \"timeline\",\n  stacked: \"card\",\n  compact: \"compact\",\n};\nconst citationVariants: Record<ResearchSessionVariant, CitationVariant> = {\n  split: \"number\",\n  stacked: \"chip\",\n  compact: \"number\",\n};\nconst statusVariants: Record<ResearchSessionVariant, ResponseStatusVariant> = {\n  split: \"inline\",\n  stacked: \"bar\",\n  compact: \"inline\",\n};\n\n/** A research run: the plan, search activity, sources, and the synthesis. Split places the plan and activity beside the synthesis at 760px. */\nexport function ResearchSession({\n  variant = \"split\",\n  children,\n  className,\n  ...props\n}: ResearchSessionProps) {\n  const id = useId();\n  return (\n    <Context.Provider value={{ id, variant }}>\n      <section\n        aria-labelledby={`${id}-title`}\n        data-slot=\"research-session\"\n        className={cn(\n          \"@container box-border min-w-0 text-[13px]/[18px] text-foreground\",\n          className,\n        )}\n        {...props}\n        data-variant={variant}\n      >\n        <div\n          className={cn(\n            \"grid min-w-0 items-start\",\n            variant === \"compact\" ? \"gap-3\" : \"gap-4\",\n            variant === \"split\" &&\n              \"@min-[760px]:grid-cols-[minmax(240px,0.8fr)_minmax(0,1.4fr)] @min-[760px]:gap-5\",\n          )}\n        >\n          {children}\n        </div>\n      </section>\n    </Context.Provider>\n  );\n}\n\nexport function ResearchSessionHeader({ className, ...props }: ComponentProps<\"header\">) {\n  const { variant } = useSession(\"ResearchSessionHeader\");\n  return (\n    <header\n      data-slot=\"research-session-header\"\n      className={cn(\n        \"grid min-w-0 @min-[760px]:col-span-full\",\n        variant === \"compact\" ? \"gap-2\" : \"gap-3\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport function ResearchSessionTitle({ className, ...props }: ComponentProps<\"h2\">) {\n  const { id, variant } = useSession(\"ResearchSessionTitle\");\n  return (\n    <h2\n      data-slot=\"research-session-title\"\n      className={cn(\n        \"m-0 font-semibold tracking-[-0.01em] wrap-anywhere\",\n        variant === \"compact\" ? \"text-[15px]/5\" : \"text-lg/6\",\n        className,\n      )}\n      {...props}\n      id={`${id}-title`}\n    />\n  );\n}\n\nexport function ResearchSessionDescription({ className, ...props }: ComponentProps<\"p\">) {\n  return (\n    <p\n      data-slot=\"research-session-description\"\n      className={cn(\"m-0 text-pretty text-muted-foreground\", className)}\n      {...props}\n    />\n  );\n}\n\n/** Overall progress. Compose Progress Summary parts inside it. */\nexport function ResearchSessionProgress(props: Omit<ProgressSummaryProps, \"variant\">) {\n  const { variant } = useSession(\"ResearchSessionProgress\");\n  return <ProgressSummary {...props} variant={progressVariants[variant]} />;\n}\n\nfunction Column({\n  part,\n  slot,\n  className,\n  ...props\n}: ComponentProps<\"div\"> & { part: string; slot: string }) {\n  const { variant } = useSession(part);\n  return (\n    <div\n      data-slot={slot}\n      className={cn(\n        \"grid min-w-0 content-start\",\n        variant === \"compact\" ? \"gap-3\" : \"gap-4\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\n/** The working column: plan and search activity. */\nexport function ResearchSessionAside(props: ComponentProps<\"div\">) {\n  return <Column {...props} part=\"ResearchSessionAside\" slot=\"research-session-aside\" />;\n}\n\n/** The reading column: synthesis and sources. */\nexport function ResearchSessionMain(props: ComponentProps<\"div\">) {\n  return <Column {...props} part=\"ResearchSessionMain\" slot=\"research-session-main\" />;\n}\n\nfunction Panel({\n  part,\n  slot,\n  className,\n  ...props\n}: ComponentProps<\"section\"> & { part: string; slot: string }) {\n  const { variant } = useSession(part);\n  const id = useId();\n  const compact = variant === \"compact\";\n  return (\n    <PanelContext.Provider value={id}>\n      <section\n        aria-labelledby={id}\n        data-slot={slot}\n        className={cn(\n          \"grid min-w-0 content-start border bg-card\",\n          compact ? \"gap-2 rounded-xl p-3\" : \"gap-3 rounded-[14px] p-4\",\n          className,\n        )}\n        {...props}\n      />\n    </PanelContext.Provider>\n  );\n}\n\n/** The research plan. Compose ResearchSessionTasks inside it. */\nexport function ResearchSessionPlan(props: ComponentProps<\"section\">) {\n  return <Panel {...props} part=\"ResearchSessionPlan\" slot=\"research-session-plan\" />;\n}\n\n/** Search activity. Compose ResearchSessionSearches inside it. */\nexport function ResearchSessionActivity(props: ComponentProps<\"section\">) {\n  return <Panel {...props} part=\"ResearchSessionActivity\" slot=\"research-session-activity\" />;\n}\n\n/** The written answer. Compose citations and ResearchSessionStatus inside it. */\nexport function ResearchSessionSynthesis(props: ComponentProps<\"section\">) {\n  return <Panel {...props} part=\"ResearchSessionSynthesis\" slot=\"research-session-synthesis\" />;\n}\n\n/** Sources the synthesis draws from. */\nexport function ResearchSessionSources(props: ComponentProps<\"section\">) {\n  return <Panel {...props} part=\"ResearchSessionSources\" slot=\"research-session-sources\" />;\n}\n\nfunction usePanel(part: string) {\n  const id = useContext(PanelContext);\n  if (!id) throw new Error(`${part} must be used within a ResearchSession panel`);\n  return id;\n}\n\nexport function ResearchSessionPanelTitle({ className, ...props }: ComponentProps<\"h3\">) {\n  const id = usePanel(\"ResearchSessionPanelTitle\");\n  return (\n    <h3\n      data-slot=\"research-session-panel-title\"\n      className={cn(\"m-0 text-[13px]/[18px] font-medium\", className)}\n      {...props}\n      id={id}\n    />\n  );\n}\n\n/** Plan steps. Compose Task List items inside it. */\nexport function ResearchSessionTasks(props: Omit<TaskListProps, \"variant\">) {\n  const { variant } = useSession(\"ResearchSessionTasks\");\n  return <TaskList {...props} variant={taskVariants[variant]} />;\n}\n\n/** Searches and reads as they happen. Compose Thinking parts inside it. */\nexport function ResearchSessionSearches({ className, ...props }: ThinkingProps) {\n  useSession(\"ResearchSessionSearches\");\n  return <Thinking className={cn(\"min-w-0\", className)} {...props} />;\n}\n\n/** Where the synthesis stands. Compose Response Status parts inside it. */\nexport function ResearchSessionStatus(props: Omit<ResponseStatusProps, \"variant\">) {\n  const { variant } = useSession(\"ResearchSessionStatus\");\n  return <ResponseStatus {...props} variant={statusVariants[variant]} />;\n}\n\nexport function ResearchSessionText({ className, ...props }: ComponentProps<\"div\">) {\n  const { variant } = useSession(\"ResearchSessionText\");\n  return (\n    <div\n      data-slot=\"research-session-text\"\n      className={cn(\n        \"grid max-w-[68ch] min-w-0 wrap-anywhere\",\n        variant === \"compact\" ? \"gap-2\" : \"gap-2.5\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\n/** An inline source marker in the synthesis. Compose Citation parts inside it. */\nexport function ResearchSessionCitation(props: Omit<CitationProps, \"variant\">) {\n  const { variant } = useSession(\"ResearchSessionCitation\");\n  return <Citation {...props} variant={citationVariants[variant]} />;\n}\n\nexport function ResearchSessionSourceList({ className, ...props }: ComponentProps<\"ol\">) {\n  const id = usePanel(\"ResearchSessionSourceList\");\n  const { variant } = useSession(\"ResearchSessionSourceList\");\n  return (\n    <ol\n      aria-labelledby={id}\n      data-slot=\"research-session-source-list\"\n      className={cn(\n        \"m-0 grid min-w-0 list-none p-0\",\n        variant === \"stacked\"\n          ? \"grid-cols-[repeat(auto-fit,minmax(min(100%,220px),1fr))]\"\n          : \"grid-cols-[minmax(0,1fr)]\",\n        variant === \"compact\" ? \"gap-1\" : \"gap-2\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport type ResearchSessionSourceProps = ComponentProps<\"li\"> & {\n  /** Source number, matching the citation markers in the synthesis. */\n  index: number;\n};\n\nexport function ResearchSessionSource({\n  index,\n  children,\n  className,\n  ...props\n}: ResearchSessionSourceProps) {\n  const { variant } = useSession(\"ResearchSessionSource\");\n  const compact = variant === \"compact\";\n  return (\n    <li\n      data-slot=\"research-session-source\"\n      className={cn(\n        \"grid min-w-0 grid-cols-[20px_minmax(0,1fr)] items-start gap-2 [transition:background-color_120ms_ease-out] hover:bg-muted motion-reduce:transition-none\",\n        compact\n          ? \"rounded-lg px-0.5 py-1\"\n          : \"rounded-[10px] bg-[color-mix(in_oklab,var(--muted)_70%,var(--card))] px-2.5 py-2\",\n        className,\n      )}\n      {...props}\n    >\n      <span\n        aria-hidden=\"true\"\n        className={cn(\n          \"mt-px grid h-4.5 place-items-center rounded-full text-[11px] font-medium text-muted-foreground tabular-nums\",\n          compact ? \"bg-muted\" : \"bg-card\",\n        )}\n      >\n        {index}\n      </span>\n      <span className=\"grid min-w-0 gap-0.5\">{children}</span>\n    </li>\n  );\n}\n\nexport function ResearchSessionSourceLink({ className, ...props }: ComponentProps<\"a\">) {\n  return (\n    <a\n      data-slot=\"research-session-source-link\"\n      className={cn(\n        \"font-medium text-foreground no-underline decoration-border-strong underline-offset-3 wrap-anywhere hover:underline focus-visible:rounded-sm focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-ring\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport function ResearchSessionSourceMeta({ className, ...props }: ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"research-session-source-meta\"\n      className={cn(\"text-[12px] text-subtle-foreground wrap-anywhere\", className)}\n      {...props}\n    />\n  );\n}\n",
      "type": "registry:component",
      "target": "@components/uai/research-session.tsx"
    }
  ],
  "categories": [
    "ai",
    "research",
    "sources"
  ],
  "type": "registry:block"
}