{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "autocomplete",
  "title": "Autocomplete",
  "description": "Suggestions cascade in under the field and one highlight glides between them as you type.",
  "dependencies": [
    "@ui-sdk/core@0.1.0-beta.2",
    "@ui-sdk/react@0.1.0-beta.2"
  ],
  "registryDependencies": [
    "@keyframery/motion"
  ],
  "files": [
    {
      "path": "registry/components/keyframery/primitives/autocomplete.tsx",
      "content": "\"use client\"\n\n/* Animated drop-in for `@ui-sdk/react/autocomplete`: same parts, same props. Swap the import and keep your code.\n   This file adds motion only. Colours, radii, shadows and spacing stay yours.\n\n   - Content: Unfold from the field (scale 0.86, 6px blur, 8px toward the field, spring in, quick out).\n   - Items: Cascade in one after another as the suggestions open.\n   - List: Glide, one highlight that springs from row to row (CSS anchor positioning).\n   - Clear button: pops in. Trigger and clear: Press. */\n\nimport {\n  AutocompleteClear as AutocompleteClearPart,\n  AutocompleteContent as AutocompleteContentPart,\n  AutocompleteItem as AutocompleteItemPart,\n  AutocompleteList as AutocompleteListPart,\n  AutocompleteTrigger as AutocompleteTriggerPart,\n} from \"@ui-sdk/react/autocomplete\"\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport * from \"@ui-sdk/react/autocomplete\"\n\nconst press =\n  \"transition-[scale,color,background-color,opacity] duration-[calc(200ms*var(--kf-speed,1))] ease-pop active:scale-[0.9] motion-reduce:transition-none!\"\n\nfunction AutocompleteContent({ className, ...props }: React.ComponentProps<typeof AutocompleteContentPart>) {\n  return (\n    <AutocompleteContentPart\n      className={cn(\n        \"group/kf-content origin-(--transform-origin) transition-[opacity,scale,translate,filter] duration-[calc(380ms*var(--kf-speed,1))] ease-spring\",\n        \"data-starting-style:scale-[0.86] data-starting-style:opacity-0 data-starting-style:blur-[6px]\",\n        \"data-[side=bottom]:data-starting-style:-translate-y-2 data-[side=top]:data-starting-style:translate-y-2\",\n        \"data-[side=left]:data-starting-style:translate-x-2 data-[side=right]:data-starting-style:-translate-x-2\",\n        \"data-ending-style:scale-[0.96] data-ending-style:opacity-0 data-ending-style:blur-[2px] data-ending-style:duration-[calc(150ms*var(--kf-speed,1))] data-ending-style:ease-house\",\n        \"motion-reduce:transition-none!\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* The list carries the highlight: a `::before` that follows whichever suggestion is highlighted.\n   Its neutral surface follows the text colour; give `before:bg-…` in className to change it. */\nfunction AutocompleteList({ className, ...props }: React.ComponentProps<typeof AutocompleteListPart>) {\n  return (\n    <AutocompleteListPart\n      className={cn(\n        \"relative isolate [anchor-scope:--kf-hl]\",\n        \"before:pointer-events-none before:absolute before:-z-10 before:bg-[color-mix(in_oklch,currentColor_9%,transparent)] before:opacity-0\",\n        \"before:[position-anchor:--kf-hl] before:top-[anchor(top)] before:right-[anchor(right)] before:bottom-[anchor(bottom)] before:left-[anchor(left)]\",\n        \"before:transition-[top,right,bottom,left,opacity] before:duration-[calc(260ms*var(--kf-speed,1))] before:ease-spring\",\n        \"has-[[data-highlighted]]:before:opacity-100\",\n        \"motion-reduce:before:transition-none!\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* Suggestions cascade while the content has its starting style, and anchor the highlight.\n   Only opacity, translate and filter carry the delay, so hovering is never slowed. */\nfunction AutocompleteItem({ className, ...props }: React.ComponentProps<typeof AutocompleteItemPart>) {\n  return (\n    <AutocompleteItemPart\n      className={cn(\n        \"transition-[opacity,translate,filter] duration-[calc(420ms*var(--kf-speed,1))] ease-spring [transition-delay:calc((min(sibling-index(),10)-1)*calc(32ms*var(--kf-speed,1)))]\",\n        \"group-data-starting-style/kf-content:translate-y-2 group-data-starting-style/kf-content:opacity-0 group-data-starting-style/kf-content:blur-[4px]\",\n        \"group-data-ending-style/kf-content:[transition-delay:0ms]\",\n        \"group-data-starting-style/kf-content:transition-none\",\n        \"data-highlighted:[anchor-name:--kf-hl]\",\n        \"motion-reduce:transition-none!\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AutocompleteTrigger({ className, ...props }: React.ComponentProps<typeof AutocompleteTriggerPart>) {\n  return (\n    <AutocompleteTriggerPart\n      className={cn(\n        press,\n        \"[&_svg]:transition-[rotate] [&_svg]:duration-[calc(420ms*var(--kf-speed,1))] [&_svg]:ease-spring data-open:[&_svg]:rotate-180 motion-reduce:[&_svg]:transition-none\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* Only in the page while there is text, so it pops in from its starting style. */\nfunction AutocompleteClear({ className, ...props }: React.ComponentProps<typeof AutocompleteClearPart>) {\n  return (\n    <AutocompleteClearPart\n      className={cn(press, \"duration-[calc(360ms*var(--kf-speed,1))] starting:scale-50 starting:opacity-0\", className)}\n      {...props}\n    />\n  )\n}\n\nexport { AutocompleteClear, AutocompleteContent, AutocompleteItem, AutocompleteList, AutocompleteTrigger }\n",
      "type": "registry:component",
      "target": "components/keyframery/primitives/autocomplete.tsx"
    },
    {
      "path": "registry/components/keyframery/autocomplete.tsx",
      "content": "\"use client\"\n\n/* Styled autocomplete: the animated primitive plus the Keyframery look. */\n\nimport {\n  Autocomplete as AutocompleteRoot,\n  AutocompleteArrow as AutocompleteArrowPart,\n  AutocompleteClear as AutocompleteClearPart,\n  AutocompleteContent as AutocompleteContentPart,\n  AutocompleteEmpty as AutocompleteEmptyPart,\n  AutocompleteGroup as AutocompleteGroupPart,\n  AutocompleteGroupLabel as AutocompleteGroupLabelPart,\n  AutocompleteInput as AutocompleteInputPart,\n  AutocompleteItem as AutocompleteItemPart,\n  AutocompleteItemIcon as AutocompleteItemIconPart,\n  AutocompleteItemText as AutocompleteItemTextPart,\n  AutocompleteLabel as AutocompleteLabelPart,\n  AutocompleteList as AutocompleteListPart,\n  AutocompleteSeparator as AutocompleteSeparatorPart,\n  AutocompleteStatus as AutocompleteStatusPart,\n  AutocompleteTrigger as AutocompleteTriggerPart,\n  createAutocompleteController,\n  type ListData,\n} from \"@/components/keyframery/primitives/autocomplete\"\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction ChevronIcon() {\n  return (\n    <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n      <path d=\"m4 6 4 4 4-4\" />\n    </svg>\n  )\n}\n\nfunction XIcon() {\n  return (\n    <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n      <path d=\"m4.5 4.5 7 7m0-7-7 7\" />\n    </svg>\n  )\n}\n\n/* Renders no element of its own. */\nfunction Autocomplete(props: React.ComponentProps<typeof AutocompleteRoot>) {\n  return <AutocompleteRoot {...props} />\n}\n\nfunction AutocompleteLabel({\n  className,\n  ...props\n}: React.ComponentProps<typeof AutocompleteLabelPart>) {\n  return (\n    <AutocompleteLabelPart\n      className={cn(\n        \"text-[13px] leading-none font-medium text-foreground data-disabled:opacity-50\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* The row that holds the input, with the clear button and the trigger laid over its right\n   edge. A leading svg sits over its left edge. */\nfunction AutocompleteControl({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"autocomplete-control\"\n      className={cn(\n        \"group/control relative flex w-full items-center\",\n        \"[&>svg]:pointer-events-none [&>svg]:absolute [&>svg]:top-2.5 [&>svg]:left-3 [&>svg]:size-4 [&>svg]:text-muted-foreground\",\n        \"[&>svg]:transition-colors [&>svg]:duration-[calc(150ms*var(--kf-speed,1))] has-[input:focus-visible]:[&>svg]:text-foreground motion-reduce:[&>svg]:transition-none\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AutocompleteInput({\n  className,\n  ...props\n}: React.ComponentProps<typeof AutocompleteInputPart>) {\n  return (\n    <AutocompleteInputPart\n      className={cn(\n        \"h-9 w-full min-w-0 rounded-[10px] bg-background px-3 text-[13px] text-foreground outline-none placeholder:text-muted-foreground\",\n        \"[&::-webkit-search-cancel-button]:appearance-none\",\n        \"[--field-line:rgb(0_0_0/0.09)] dark:[--field-line:rgb(255_255_255/0.1)]\",\n        \"shadow-[0_0_0_1px_var(--field-line),0_1px_2px_rgb(0_0_0/0.05)] dark:shadow-[0_0_0_1px_var(--field-line)]\",\n        \"transition-[box-shadow] duration-[calc(150ms*var(--kf-speed,1))] ease-house motion-reduce:transition-none!\",\n        \"hover:[--field-line:rgb(0_0_0/0.16)] dark:hover:[--field-line:rgb(255_255_255/0.18)]\",\n        \"focus-visible:ring-[3px] focus-visible:ring-ring/25 focus-visible:[--field-line:var(--ring)] dark:focus-visible:[--field-line:var(--ring)]\",\n        \"aria-invalid:ring-destructive/25 aria-invalid:[--field-line:var(--destructive)] dark:aria-invalid:[--field-line:var(--destructive)]\",\n        \"data-readonly:bg-muted/50\",\n        \"data-disabled:cursor-not-allowed data-disabled:bg-muted data-disabled:text-muted-foreground\",\n        /* Room for what the control lays over it. */\n        \"group-has-[>svg]/control:pl-9\",\n        \"group-has-[[data-slot=autocomplete-trigger]]/control:pr-9 group-has-[[data-slot=autocomplete-clear]]/control:pr-9\",\n        \"group-has-[[data-slot=autocomplete-trigger]]/control:group-has-[[data-slot=autocomplete-clear]]/control:pr-16\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nconst controlButton =\n  \"absolute top-1 grid size-7 cursor-pointer place-items-center rounded-[7px] text-muted-foreground outline-none hover:bg-foreground/[0.06] hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring data-disabled:pointer-events-none data-disabled:opacity-40 [&_svg]:size-4\"\n\nfunction AutocompleteTrigger({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof AutocompleteTriggerPart>) {\n  return (\n    <AutocompleteTriggerPart\n      className={cn(\n        controlButton,\n        \"right-1\",\n        className,\n      )}\n      {...props}\n    >\n      {children ?? <ChevronIcon />}\n    </AutocompleteTriggerPart>\n  )\n}\n\n/* Only in the page while there is text, so it enters from its starting style. */\nfunction AutocompleteClear({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof AutocompleteClearPart>) {\n  return (\n    <AutocompleteClearPart\n      className={cn(\n        controlButton,\n        \"right-1 group-has-[[data-slot=autocomplete-trigger]]/control:right-8 [&_svg]:size-3.5\",\n        className,\n      )}\n      {...props}\n    >\n      {children ?? <XIcon />}\n    </AutocompleteClearPart>\n  )\n}\n\nfunction AutocompleteContent({\n  className,\n  children,\n  sideOffset = 6,\n  ...props\n}: React.ComponentProps<typeof AutocompleteContentPart>) {\n  return (\n    <AutocompleteContentPart\n      sideOffset={sideOffset}\n      className={cn(\n        \"group/content flex w-(--anchor-width) min-w-[200px] flex-col rounded-[14px] bg-popover text-popover-foreground outline-none\",\n        \"[--list-height:var(--available-height)]\",\n        \"shadow-[0_0_0_1px_rgb(0_0_0/0.06),0_2px_6px_-2px_rgb(0_0_0/0.08),0_12px_32px_-8px_rgb(0_0_0/0.18)]\",\n        \"dark:shadow-[0_0_0_1px_rgb(255_255_255/0.08),0_12px_32px_-8px_rgb(0_0_0/0.7)]\",\n        className,\n      )}\n      {...props}\n    >\n      {children ?? <AutocompleteList />}\n    </AutocompleteContentPart>\n  )\n}\n\nfunction AutocompleteArrow({\n  className,\n  ...props\n}: React.ComponentProps<typeof AutocompleteArrowPart>) {\n  return (\n    <AutocompleteArrowPart\n      className={cn(\"size-2.5 rotate-45 rounded-[2px] bg-popover\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction AutocompleteList({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof AutocompleteListPart>) {\n  return (\n    <AutocompleteListPart\n      className={cn(\n        \"max-h-[min(calc(var(--list-height,100vh)-8px),18rem)] scroll-py-1.5 overflow-y-auto overscroll-contain rounded-[14px] p-1.5 outline-none\",\n        \"group-has-[[data-slot=autocomplete-empty][data-empty]]/content:hidden\",\n        /* The gliding highlight, in the row's shape and colour. */\n        \"before:rounded-[8px] before:bg-accent\",\n        className,\n      )}\n      {...props}\n    >\n      {children ?? ((state) => <AutocompleteItems items={state.items as ListData<string>} />)}\n    </AutocompleteListPart>\n  )\n}\n\nfunction AutocompleteItem({\n  className,\n  ...props\n}: React.ComponentProps<typeof AutocompleteItemPart>) {\n  return (\n    <AutocompleteItemPart\n      className={cn(\n        \"group/item relative flex min-h-8 cursor-default items-center gap-2.5 rounded-[8px] px-2.5 py-1.5 text-[13px] leading-[1.3] outline-none select-none\",\n        \"data-highlighted:text-accent-foreground\",\n        \"data-disabled:pointer-events-none data-disabled:opacity-40\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* The matched part of the suggestion reads stronger; the rest steps back slightly. */\nfunction AutocompleteItemText({\n  className,\n  ...props\n}: React.ComponentProps<typeof AutocompleteItemTextPart>) {\n  return (\n    <AutocompleteItemTextPart\n      className={cn(\n        \"min-w-0 flex-1 truncate\",\n        \"data-matched:text-foreground/70 [&_mark]:bg-transparent [&_mark]:font-semibold [&_mark]:text-foreground\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AutocompleteItemIcon({\n  className,\n  ...props\n}: React.ComponentProps<typeof AutocompleteItemIconPart>) {\n  return (\n    <AutocompleteItemIconPart\n      className={cn(\n        \"grid size-4 shrink-0 place-items-center text-muted-foreground transition-colors duration-[calc(100ms*var(--kf-speed,1))] group-data-highlighted/item:text-foreground data-mirror:rtl:-scale-x-100 motion-reduce:transition-none! [&_svg]:size-4\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AutocompleteGroup({\n  className,\n  ...props\n}: React.ComponentProps<typeof AutocompleteGroupPart>) {\n  return <AutocompleteGroupPart className={cn(\"flex flex-col\", className)} {...props} />\n}\n\nfunction AutocompleteGroupLabel({\n  className,\n  ...props\n}: React.ComponentProps<typeof AutocompleteGroupLabelPart>) {\n  return (\n    <AutocompleteGroupLabelPart\n      className={cn(\n        \"px-2.5 pt-2 pb-1.5 text-[11px] leading-none font-medium text-muted-foreground select-none\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AutocompleteSeparator({\n  className,\n  ...props\n}: React.ComponentProps<typeof AutocompleteSeparatorPart>) {\n  return (\n    <AutocompleteSeparatorPart\n      className={cn(\"-mx-1.5 my-1.5 h-px bg-border\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction AutocompleteEmpty({\n  className,\n  ...props\n}: React.ComponentProps<typeof AutocompleteEmptyPart>) {\n  return (\n    <AutocompleteEmptyPart\n      className={cn(\n        \"hidden px-3 py-6 text-center text-[13px] text-muted-foreground data-empty:block data-loading:block\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AutocompleteStatus({\n  className,\n  ...props\n}: React.ComponentProps<typeof AutocompleteStatusPart>) {\n  return (\n    <AutocompleteStatusPart\n      className={cn(\n        \"px-4 pt-3 pb-1 text-[12px] text-muted-foreground tabular-nums empty:hidden\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* Renders suggestions passed as data with the styled parts above. */\nfunction AutocompleteItems({ items }: { items?: ListData<string> }) {\n  return (items ?? []).map((entry, index) => {\n    if (typeof entry === \"string\") {\n      return (\n        <AutocompleteItem key={entry} value={entry}>\n          <AutocompleteItemText />\n        </AutocompleteItem>\n      )\n    }\n    if (\"type\" in entry && entry.type === \"separator\") {\n      return <AutocompleteSeparator key={`separator-${index}`} />\n    }\n    if (\"type\" in entry && entry.type === \"group\") {\n      return (\n        <AutocompleteGroup key={`group-${entry.label ?? index}`}>\n          {entry.label && <AutocompleteGroupLabel>{entry.label}</AutocompleteGroupLabel>}\n          <AutocompleteItems items={entry.items} />\n        </AutocompleteGroup>\n      )\n    }\n    const { value, label, disabled, keywords } = entry\n    return (\n      <AutocompleteItem\n        key={value}\n        value={value}\n        label={label}\n        disabled={disabled}\n        keywords={keywords}\n      >\n        <AutocompleteItemText />\n      </AutocompleteItem>\n    )\n  })\n}\n\nexport {\n  Autocomplete,\n  AutocompleteArrow,\n  AutocompleteClear,\n  AutocompleteContent,\n  AutocompleteControl,\n  AutocompleteEmpty,\n  AutocompleteGroup,\n  AutocompleteGroupLabel,\n  AutocompleteInput,\n  AutocompleteItem,\n  AutocompleteItemIcon,\n  AutocompleteItems,\n  AutocompleteItemText,\n  AutocompleteLabel,\n  AutocompleteList,\n  AutocompleteSeparator,\n  AutocompleteStatus,\n  AutocompleteTrigger,\n  createAutocompleteController,\n}\n",
      "type": "registry:component",
      "target": "components/keyframery/autocomplete.tsx"
    }
  ],
  "type": "registry:component"
}