'use client'; import * as React from 'react'; import { type HTMLMotionProps, isMotionComponent, motion } from 'motion/react'; import { cn } from '@/lib/utils'; type AnyProps = Record; type DOMMotionProps = Omit< HTMLMotionProps, 'ref' > & { ref?: React.Ref }; type WithAsChild = | (Base & { asChild: true; children: React.ReactElement }) | (Base & { asChild?: false | undefined }); type SlotProps = { // eslint-disable-next-line @typescript-eslint/no-explicit-any children?: any; } & DOMMotionProps; function mergeRefs( ...refs: (React.Ref | undefined)[] ): React.RefCallback { return (node) => { refs.forEach((ref) => { if (!ref) return; if (typeof ref === 'function') { ref(node); } else { (ref as React.RefObject).current = node; } }); }; } function mergeProps( childProps: AnyProps, slotProps: DOMMotionProps, ): AnyProps { const merged: AnyProps = { ...childProps, ...slotProps }; if (childProps.className || slotProps.className) { merged.className = cn( childProps.className as string, slotProps.className as string, ); } if (childProps.style || slotProps.style) { merged.style = { ...(childProps.style as React.CSSProperties), ...(slotProps.style as React.CSSProperties), }; } return merged; } function Slot({ children, ref, ...props }: SlotProps) { const isAlreadyMotion = typeof children.type === 'object' && children.type !== null && isMotionComponent(children.type); const Base = React.useMemo( () => isAlreadyMotion ? (children.type as React.ElementType) : motion.create(children.type as React.ElementType), [isAlreadyMotion, children.type], ); if (!React.isValidElement(children)) return null; const { ref: childRef, ...childProps } = children.props as AnyProps; const mergedProps = mergeProps(childProps, props); return ( , ref)} /> ); } export { Slot, type SlotProps, type WithAsChild, type DOMMotionProps, type AnyProps, };