{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "p-autocomplete-12",
  "description": "Autocomplete with async items loading",
  "registryDependencies": [
    "@coss/autocomplete",
    "@coss/spinner"
  ],
  "files": [
    {
      "path": "registry/default/particles/p-autocomplete-12.tsx",
      "content": "\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { useEffect, useState } from \"react\";\nimport {\n  Autocomplete,\n  AutocompleteInput,\n  AutocompleteItem,\n  AutocompleteList,\n  AutocompletePopup,\n  AutocompleteStatus,\n  useAutocompleteFilter,\n} from \"@/registry/default/ui/autocomplete\";\nimport { Spinner } from \"@/registry/default/ui/spinner\";\n\ntype Movie = { id: string; title: string; year: number };\nconst top100Movies: Movie[] = [\n  { id: \"1\", title: \"The Shawshank Redemption\", year: 1994 },\n  { id: \"2\", title: \"The Godfather\", year: 1972 },\n  { id: \"3\", title: \"The Dark Knight\", year: 2008 },\n  { id: \"4\", title: \"The Godfather Part II\", year: 1974 },\n  { id: \"5\", title: \"12 Angry Men\", year: 1957 },\n  { id: \"8\", title: \"Pulp Fiction\", year: 1994 },\n  { id: \"11\", title: \"Forrest Gump\", year: 1994 },\n  { id: \"14\", title: \"Inception\", year: 2010 },\n];\n\nasync function searchMovies(\n  query: string,\n  filter: (item: string, query: string) => boolean,\n): Promise<Movie[]> {\n  await new Promise((resolve) =>\n    setTimeout(resolve, Math.random() * 500 + 100),\n  );\n  if (Math.random() < 0.01 || query === \"will_error\") {\n    throw new Error(\"Network error\");\n  }\n  return top100Movies.filter(\n    (movie) =>\n      filter(movie.title, query) || filter(movie.year.toString(), query),\n  );\n}\n\nexport default function Particle() {\n  const [searchValue, setSearchValue] = useState(\"\");\n  const [isLoading, setIsLoading] = useState(false);\n  const [searchResults, setSearchResults] = useState<Movie[]>([]);\n  const [error, setError] = useState<string | null>(null);\n\n  const { contains } = useAutocompleteFilter({ sensitivity: \"base\" });\n\n  useEffect(() => {\n    if (!searchValue) {\n      setSearchResults([]);\n      setIsLoading(false);\n      return;\n    }\n\n    setIsLoading(true);\n    setError(null);\n    let ignore = false;\n\n    const timeoutId = setTimeout(async () => {\n      try {\n        const results = await searchMovies(searchValue, contains);\n        if (!ignore) setSearchResults(results);\n      } catch {\n        if (!ignore) {\n          setError(\"Failed to fetch movies. Please try again.\");\n          setSearchResults([]);\n        }\n      } finally {\n        if (!ignore) setIsLoading(false);\n      }\n    }, 300);\n\n    return () => {\n      clearTimeout(timeoutId);\n      ignore = true;\n    };\n  }, [searchValue, contains]);\n\n  let status: ReactNode = `${searchResults.length} result${searchResults.length === 1 ? \"\" : \"s\"} found`;\n  if (isLoading) {\n    status = (\n      <span className=\"flex items-center justify-between gap-2 text-muted-foreground\">\n        Searching...\n        <Spinner className=\"size-4.5 sm:size-4\" />\n      </span>\n    );\n  } else if (error) {\n    status = (\n      <span className=\"font-normal text-destructive text-sm\">{error}</span>\n    );\n  } else if (searchResults.length === 0 && searchValue) {\n    status = (\n      <span className=\"font-normal text-muted-foreground text-sm\">\n        Movie or year \"{searchValue}\" does not exist in the Top 100 IMDb movies\n      </span>\n    );\n  }\n\n  const shouldRenderPopup = searchValue !== \"\";\n\n  return (\n    <Autocomplete\n      filter={null}\n      items={searchResults}\n      itemToStringValue={(item: unknown) => (item as Movie).title}\n      onValueChange={setSearchValue}\n      value={searchValue}\n    >\n      <AutocompleteInput placeholder=\"e.g. Pulp Fiction or 1994\" />\n      {shouldRenderPopup && (\n        <AutocompletePopup aria-busy={isLoading || undefined}>\n          <AutocompleteStatus className=\"text-muted-foreground\">\n            {status}\n          </AutocompleteStatus>\n          <AutocompleteList>\n            {(movie: Movie) => (\n              <AutocompleteItem key={movie.id} value={movie}>\n                <div className=\"flex w-full flex-col gap-1\">\n                  <div className=\"font-medium\">{movie.title}</div>\n                  <div className=\"text-muted-foreground text-xs\">\n                    {movie.year}\n                  </div>\n                </div>\n              </AutocompleteItem>\n            )}\n          </AutocompleteList>\n        </AutocompletePopup>\n      )}\n    </Autocomplete>\n  );\n}\n",
      "type": "registry:block"
    }
  ],
  "meta": {
    "className": "**:data-[slot=preview]:w-full **:data-[slot=preview]:max-w-64"
  },
  "categories": [
    "autocomplete",
    "input",
    "async"
  ],
  "type": "registry:block"
}