{
  "title": "Select",
  "description": "Displays a list of options for the user to pick from-triggered by a button-with spring popup reveals, shared gliding active item highlight, and animated checkmarks.",
  "name": "motion-select",
  "dependencies": [
    "motion",
    "@base-ui/react",
    "lucide-react"
  ],
  "registryDependencies": [],
  "type": "registry:ui",
  "files": [
    {
      "path": "components/paceui/motion/select.tsx",
      "type": "registry:ui",
      "content": "import * as React from \"react\";\n\nimport { Select as SelectPrimitive } from \"@base-ui/react/select\";\nimport { CheckIcon, ChevronDownIcon, ChevronUpIcon } from \"lucide-react\";\nimport { AnimatePresence, type HTMLMotionProps, LayoutGroup, type Transition, motion } from \"motion/react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface SelectRootContextType {\n    stagger?: boolean | number;\n}\n\nconst SelectRootContext = React.createContext<SelectRootContextType>({});\n\ninterface SelectHighlightContextType {\n    highlightLayoutId: string;\n    activeItemId: string | null;\n    setActiveItem: (id: string) => void;\n    clearActiveItemWithDelay: () => void;\n    stagger?: boolean | number;\n    getItemIndex: (id: string) => number;\n}\n\nconst SelectHighlightContext = React.createContext<SelectHighlightContextType | null>(null);\n\nexport type SelectProps<ItemValue = any, Multiple extends boolean = boolean> = SelectPrimitive.Root.Props<\n    ItemValue,\n    Multiple\n> & {\n    stagger?: boolean | number;\n};\n\nfunction Select<ItemValue = any, Multiple extends boolean = boolean>({\n    stagger,\n    ...props\n}: SelectProps<ItemValue, Multiple>) {\n    const rootContextValue = React.useMemo(() => ({ stagger }), [stagger]);\n\n    return (\n        <SelectRootContext.Provider value={rootContextValue}>\n            <SelectPrimitive.Root data-slot=\"select\" {...props} />\n        </SelectRootContext.Provider>\n    );\n}\n\nfunction SelectGroup({ className, ...props }: SelectPrimitive.Group.Props) {\n    return <SelectPrimitive.Group data-slot=\"select-group\" className={cn(\"scroll-my-1 p-1\", className)} {...props} />;\n}\n\nfunction SelectValue({ className, ...props }: SelectPrimitive.Value.Props) {\n    return (\n        <SelectPrimitive.Value data-slot=\"select-value\" className={cn(\"flex flex-1 text-left\", className)} {...props} />\n    );\n}\n\nexport interface SelectTriggerProps extends SelectPrimitive.Trigger.Props {\n    size?: \"default\" | \"sm\" | \"xs\" | \"lg\";\n}\n\nfunction SelectTrigger({ className, size = \"default\", children, ...props }: SelectTriggerProps) {\n    return (\n        <SelectPrimitive.Trigger\n            data-slot=\"select-trigger\"\n            data-size={size}\n            className={cn(\n                \"border-input data-placeholder:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 flex w-fit items-center justify-between gap-1.5 rounded-md border bg-transparent py-2 pr-2 pl-2.5 text-sm font-medium whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-[3px] data-[size=default]:h-9 data-[size=sm]:h-8 data-[size=xs]:h-6 data-[size=xs]:gap-1 data-[size=xs]:rounded-[min(var(--radius-md),8px)] data-[size=xs]:py-1 data-[size=xs]:pr-1.5 data-[size=xs]:pl-2 data-[size=xs]:text-xs data-[size=lg]:h-10 data-[size=lg]:py-2.5 data-[size=lg]:pr-2.5 data-[size=lg]:pl-3 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 in-data-[size=xs]:[&_svg:not([class*='size-'])]:size-3\",\n                className,\n            )}\n            {...props}>\n            {children}\n            <SelectPrimitive.Icon\n                render={\n                    <ChevronDownIcon className=\"text-muted-foreground pointer-events-none size-4 transition-transform duration-200 in-data-[popup-open]:rotate-180 in-data-[size=xs]:size-3\" />\n                }\n            />\n        </SelectPrimitive.Trigger>\n    );\n}\n\ninterface SelectContentListProps {\n    children: React.ReactNode;\n    highlightLayoutId: string;\n    stagger?: boolean | number;\n}\n\nfunction SelectContentList({ children, highlightLayoutId, stagger }: SelectContentListProps) {\n    const [activeItemId, setActiveItemId] = React.useState<string | null>(null);\n    const timeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);\n    const itemIdsRef = React.useRef<string[]>([]);\n\n    const setActiveItem = React.useCallback((id: string) => {\n        if (timeoutRef.current) clearTimeout(timeoutRef.current);\n        setActiveItemId(id);\n    }, []);\n\n    const clearActiveItemWithDelay = React.useCallback(() => {\n        if (timeoutRef.current) clearTimeout(timeoutRef.current);\n        timeoutRef.current = setTimeout(() => {\n            setActiveItemId(null);\n        }, 180);\n    }, []);\n\n    const getItemIndex = React.useCallback((id: string) => {\n        let index = itemIdsRef.current.indexOf(id);\n        if (index === -1) {\n            index = itemIdsRef.current.length;\n            itemIdsRef.current.push(id);\n        }\n        return index;\n    }, []);\n\n    const contextValue = React.useMemo<SelectHighlightContextType>(\n        () => ({\n            highlightLayoutId,\n            activeItemId,\n            setActiveItem,\n            clearActiveItemWithDelay,\n            stagger,\n            getItemIndex,\n        }),\n        [highlightLayoutId, activeItemId, setActiveItem, clearActiveItemWithDelay, stagger, getItemIndex],\n    );\n\n    return (\n        <SelectHighlightContext.Provider value={contextValue}>\n            <LayoutGroup id={highlightLayoutId}>\n                <div onPointerLeave={clearActiveItemWithDelay} className=\"contents\">\n                    <SelectScrollUpButton />\n                    <SelectPrimitive.List className=\"overflow-hidden\">{children}</SelectPrimitive.List>\n                    <SelectScrollDownButton />\n                </div>\n            </LayoutGroup>\n        </SelectHighlightContext.Provider>\n    );\n}\n\nexport interface SelectContentProps\n    extends\n    SelectPrimitive.Popup.Props,\n    Pick<\n        SelectPrimitive.Positioner.Props,\n        \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\" | \"alignItemWithTrigger\"\n    > {\n    stagger?: boolean | number;\n    transition?: Transition;\n}\n\nfunction SelectContent({\n    className,\n    children,\n    side = \"bottom\",\n    sideOffset = 4,\n    align = \"start\",\n    alignOffset = 0,\n    alignItemWithTrigger = false,\n    stagger: staggerProp,\n    transition = { type: \"spring\", stiffness: 420, damping: 28, mass: 0.8 },\n    ...props\n}: SelectContentProps) {\n    const rootContext = React.useContext(SelectRootContext);\n    const resolvedStagger = staggerProp ?? rootContext.stagger ?? true;\n    const highlightLayoutId = React.useId();\n\n    return (\n        <SelectPrimitive.Portal>\n            <SelectPrimitive.Positioner\n                side={side}\n                sideOffset={sideOffset}\n                align={align}\n                alignOffset={alignOffset}\n                alignItemWithTrigger={alignItemWithTrigger}\n                className=\"isolate z-500 outline-none\">\n                <SelectPrimitive.Popup\n                    data-slot=\"select-content\"\n                    {...props}\n                    render={(popupProps, state) => (\n                        <AnimatePresence>\n                            {state.open && (\n                                <motion.div\n                                    {...(popupProps as unknown as HTMLMotionProps<\"div\">)}\n                                    key=\"select-popup\"\n                                    initial={{\n                                        opacity: 0,\n                                        scale: 0.95,\n                                        y: side === \"bottom\" ? -8 : side === \"top\" ? 8 : 0,\n                                        x: side === \"right\" ? -10 : side === \"left\" ? 10 : 0,\n                                    }}\n                                    animate={{ opacity: 1, scale: 1, y: 0, x: 0 }}\n                                    exit={{\n                                        opacity: 0,\n                                        scale: 0.95,\n                                        y: side === \"bottom\" ? -6 : side === \"top\" ? 6 : 0,\n                                        x: side === \"right\" ? -8 : side === \"left\" ? 8 : 0,\n                                    }}\n                                    transition={transition}\n                                    className={cn(\n                                        \"bg-popover text-popover-foreground ring-foreground/10 no-scrollbar relative isolate z-500 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md shadow-md ring-1\",\n                                        className,\n                                    )}>\n                                    <SelectContentList\n                                        stagger={resolvedStagger}\n                                        highlightLayoutId={highlightLayoutId}>\n                                        {children}\n                                    </SelectContentList>\n                                </motion.div>\n                            )}\n                        </AnimatePresence>\n                    )}\n                />\n            </SelectPrimitive.Positioner>\n        </SelectPrimitive.Portal>\n    );\n}\n\nfunction SelectLabel({ className, ...props }: SelectPrimitive.GroupLabel.Props) {\n    return (\n        <SelectPrimitive.GroupLabel\n            data-slot=\"select-label\"\n            className={cn(\"text-muted-foreground px-2 py-1.5 text-xs\", className)}\n            {...props}\n        />\n    );\n}\n\nexport interface SelectItemProps extends SelectPrimitive.Item.Props {\n    stagger?: boolean | number;\n}\n\nfunction SelectItem({ className, children, stagger: itemStagger, ...props }: SelectItemProps) {\n    const highlightContext = React.useContext(SelectHighlightContext);\n    const itemId = React.useId();\n\n    return (\n        <SelectPrimitive.Item\n            data-slot=\"select-item\"\n            className={className}\n            {...props}\n            render={(itemProps, state) => {\n                const isCurrentActive = highlightContext?.activeItemId === itemId;\n                const effectiveStagger = itemStagger ?? highlightContext?.stagger ?? true;\n                const isStaggerEnabled = effectiveStagger !== false;\n                const staggerDelay = typeof effectiveStagger === \"number\" ? effectiveStagger : 0.025;\n                const itemIndex = isStaggerEnabled && highlightContext ? highlightContext.getItemIndex(itemId) : 0;\n                const delay = Math.min(itemIndex * staggerDelay, 0.25);\n\n                return (\n                    <motion.div\n                        {...(itemProps as unknown as HTMLMotionProps<\"div\">)}\n                        initial={isStaggerEnabled ? { opacity: 0, x: -10 } : false}\n                        animate={isStaggerEnabled ? { opacity: 1, x: 0 } : false}\n                        transition={{\n                            x: { type: \"spring\", stiffness: 420, damping: 28, mass: 0.8, delay },\n                            opacity: { duration: 0.2, delay },\n                            scale: { type: \"spring\", stiffness: 400, damping: 25 },\n                            default: { type: \"spring\", stiffness: 400, damping: 25 },\n                        }}\n                        onPointerEnter={(e: React.PointerEvent<HTMLDivElement>) => {\n                            itemProps.onPointerEnter?.(e);\n                            highlightContext?.setActiveItem(itemId);\n                        }}\n                        onFocus={(e: React.FocusEvent<HTMLDivElement>) => {\n                            itemProps.onFocus?.(e);\n                            highlightContext?.setActiveItem(itemId);\n                        }}\n                        whileTap={{ scale: 0.98 }}\n                        className={cn(\n                            \"group/select-item relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2\",\n                            (state.highlighted || isCurrentActive) && \"text-accent-foreground\",\n                            className,\n                        )}>\n                        {isCurrentActive && highlightContext?.highlightLayoutId && (\n                            <motion.div\n                                layoutId={highlightContext.highlightLayoutId}\n                                layout=\"position\"\n                                className=\"bg-accent pointer-events-none absolute inset-0 z-0 rounded-sm\"\n                                transition={{ type: \"spring\", stiffness: 450, damping: 32 }}\n                            />\n                        )}\n                        <SelectPrimitive.ItemText className=\"relative z-10 flex flex-1 shrink-0 gap-2 whitespace-nowrap\">\n                            {children}\n                        </SelectPrimitive.ItemText>\n                        <span\n                            className=\"pointer-events-none absolute right-2 z-10 flex size-4 items-center justify-center\"\n                            data-slot=\"select-item-indicator\">\n                            <SelectPrimitive.ItemIndicator>\n                                <motion.span\n                                    initial={{ scale: 0, opacity: 0 }}\n                                    animate={{ scale: 1, opacity: 1 }}\n                                    exit={{ scale: 0, opacity: 0 }}\n                                    transition={{ type: \"spring\", stiffness: 450, damping: 22 }}\n                                    className=\"flex items-center justify-center\">\n                                    <CheckIcon className=\"pointer-events-none size-4\" />\n                                </motion.span>\n                            </SelectPrimitive.ItemIndicator>\n                        </span>\n                    </motion.div>\n                );\n            }}\n        />\n    );\n}\n\nfunction SelectSeparator({ className, ...props }: SelectPrimitive.Separator.Props) {\n    return (\n        <SelectPrimitive.Separator\n            data-slot=\"select-separator\"\n            className={cn(\"bg-border pointer-events-none -mx-1 my-1 h-px\", className)}\n            {...props}\n        />\n    );\n}\n\nfunction SelectScrollUpButton({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.ScrollUpArrow>) {\n    return (\n        <SelectPrimitive.ScrollUpArrow\n            data-slot=\"select-scroll-up-button\"\n            className={cn(\n                \"bg-popover top-0 z-10 flex w-full cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4\",\n                className,\n            )}\n            {...props}>\n            <ChevronUpIcon />\n        </SelectPrimitive.ScrollUpArrow>\n    );\n}\n\nfunction SelectScrollDownButton({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.ScrollDownArrow>) {\n    return (\n        <SelectPrimitive.ScrollDownArrow\n            data-slot=\"select-scroll-down-button\"\n            className={cn(\n                \"bg-popover bottom-0 z-10 flex w-full cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4\",\n                className,\n            )}\n            {...props}>\n            <ChevronDownIcon />\n        </SelectPrimitive.ScrollDownArrow>\n    );\n}\n\nexport {\n    Select,\n    SelectContent,\n    SelectGroup,\n    SelectItem,\n    SelectLabel,\n    SelectScrollDownButton,\n    SelectScrollUpButton,\n    SelectSeparator,\n    SelectTrigger,\n    SelectValue,\n};\n"
    }
  ],
  "mcp": {
    "description": "Displays a customizable select menu with options. Provides smooth spring popup reveals, shared gliding active item highlight, and selection checkmark animations.",
    "tags": [
      "component",
      "select",
      "dropdown",
      "form",
      "paceui",
      "animation"
    ]
  }
}