{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "follow-up-suggestions",
  "type": "registry:component",
  "title": "Follow Up Suggestions",
  "description": "Prompt chips rendered from runtime generated follow up suggestions.",
  "registryDependencies": [],
  "dependencies": [
    "@assistant-ui/react"
  ],
  "files": [
    {
      "type": "registry:component",
      "path": "components/assistant-ui/follow-up-suggestions.tsx",
      "content": "\"use client\";\n\nimport { AuiIf, useAuiState, ThreadPrimitive } from \"@assistant-ui/react\";\nimport { useCallback, useEffect, useRef, useState, type FC } from \"react\";\n\nconst FollowupSuggestionsRow: FC = () => {\n  const suggestions = useAuiState((s) => s.thread.suggestions);\n  const scrollRef = useRef<HTMLDivElement>(null);\n  const rtlRef = useRef<boolean | null>(null);\n  const [fades, setFades] = useState({ left: false, right: false });\n\n  const updateFades = useCallback(() => {\n    const el = scrollRef.current;\n    if (!el) return;\n    const maxScroll = el.scrollWidth - el.clientWidth;\n    // scrollLeft runs 0..-max in RTL; normalize to hidden width per physical edge.\n    const fromStart = Math.abs(el.scrollLeft);\n    // getComputedStyle forces a style recalc per scroll event; direction is stable, read it once.\n    const rtl = (rtlRef.current ??= getComputedStyle(el).direction === \"rtl\");\n    const [left, right] = rtl\n      ? [maxScroll - fromStart, fromStart]\n      : [fromStart, maxScroll - fromStart];\n    setFades((prev) => {\n      const next = { left: left > 1, right: right > 1 };\n      return prev.left === next.left && prev.right === next.right ? prev : next;\n    });\n  }, []);\n\n  useEffect(() => {\n    updateFades();\n    const el = scrollRef.current;\n    if (!el?.firstElementChild) return undefined;\n    const observer = new ResizeObserver(updateFades);\n    observer.observe(el);\n    observer.observe(el.firstElementChild);\n    return () => observer.disconnect();\n  }, [updateFades]);\n\n  const maskImage = `linear-gradient(to right, ${\n    fades.left ? \"transparent, black 2rem\" : \"black\"\n  }, ${fades.right ? \"black calc(100% - 2rem), transparent\" : \"black\"})`;\n\n  return (\n    <div\n      ref={scrollRef}\n      onScroll={updateFades}\n      // overflow-x clips both axes; py-1/-my-1 gives focus rings vertical room without changing outer height.\n      className=\"aui-thread-followup-suggestions -my-1 w-full overflow-x-auto py-1 [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\n      style={{ maskImage, WebkitMaskImage: maskImage }}\n    >\n      <div className=\"mx-auto flex min-h-8 w-max items-center gap-2 px-0.5\">\n        {suggestions.map((suggestion, idx) => (\n          <ThreadPrimitive.Suggestion\n            key={idx}\n            className=\"aui-thread-followup-suggestion bg-background hover:bg-muted/80 rounded-full border px-3 py-1 text-sm whitespace-nowrap transition-colors ease-in\"\n            prompt={suggestion.prompt}\n            method=\"replace\"\n            autoSend\n          >\n            {suggestion.prompt}\n          </ThreadPrimitive.Suggestion>\n        ))}\n      </div>\n    </div>\n  );\n};\n\nexport const ThreadFollowupSuggestions: FC = () => (\n  <AuiIf\n    condition={(s) =>\n      !s.thread.isEmpty &&\n      !s.thread.isRunning &&\n      s.thread.suggestions.length > 0\n    }\n  >\n    <FollowupSuggestionsRow />\n  </AuiIf>\n);\n"
    }
  ]
}