{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "animated-menu",
  "title": "Animated Menu",
  "description": "Animated menu, with orchestrated children animation, fully customizable.",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "registry/blocks/animated-menu/index.tsx",
      "content": "'use client';\nimport { cn } from '@/lib/utils';\nimport { cva, VariantProps } from 'class-variance-authority';\nimport {\n  AnimatePresence,\n  HTMLMotionProps,\n  motion,\n  MotionConfig,\n  Variants,\n} from 'motion/react';\nimport React from 'react';\n\nconst menuListVariants = {\n  open: {\n    width: 320,\n    height: 420,\n    transition: { duration: 0.75, ease: [0.76, 0, 0.24, 1] },\n  },\n  close: {\n    width: 80,\n    height: 32,\n    transition: { duration: 0.75, delay: 0.2, ease: [0.76, 0, 0.24, 1] },\n  },\n} as Variants;\n\nconst itemVariants = {\n  initial: {\n    opacity: 0,\n  },\n  enter: (i: number) => ({\n    opacity: 1,\n    transition: {\n      delay: 0.55 + i * 0.1,\n      duration: 0.75,\n    },\n  }),\n  exit: (i: number) => ({\n    opacity: 0,\n    transition: {\n      delay: 0.25 + -i * 0.1,\n    },\n  }),\n} as Variants;\ninterface AnimatedMenuContextValue {\n  isOpen: boolean;\n  setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;\n}\ninterface AnimatedMenuListProps extends HTMLMotionProps<'div'> {\n  menuListVariants?: Variants;\n}\ninterface AnimatedMenuItemProps extends HTMLMotionProps<'div'> {\n  order?: number;\n  variants?: Variants;\n}\ninterface AnimatedMenuButtonLabelProps\n  extends React.HTMLAttributes<HTMLDivElement> {\n  closeLabel?: string;\n  openLabel?: string;\n}\nconst AnimatedMenuContext = React.createContext<\n  AnimatedMenuContextValue | undefined\n>(undefined);\nfunction useAnimatedMenuContext() {\n  const context = React.useContext(AnimatedMenuContext);\n  if (context === undefined) {\n    throw new Error(\n      'useAnimatedMenuContext must be used within an AnimatedMenuProvider',\n    );\n  }\n  return context;\n}\nexport function AnimatedMenu({\n  className,\n  ...props\n}: React.ComponentProps<'div'>) {\n  const [isOpen, setIsOpen] = React.useState<boolean>(false);\n\n  return (\n    <AnimatedMenuContext.Provider value={{ isOpen, setIsOpen }}>\n      <div className={cn('relative', className)} {...props} />\n    </AnimatedMenuContext.Provider>\n  );\n}\nconst buttonIconVariants = cva(\n  'flex flex-col gap-1.5 justify-center items-center p-1 relative *:bg-current',\n  {\n    variants: {\n      size: {\n        sm: '*:w-4 *:h-[1.5px] *:origin-[17%]',\n        md: '*:w-6 *:h-0.5  *:origin-[25%]',\n        lg: '*:w-8 *:h-0.5  *:origin-[33%]',\n        xl: '*:w-10 *:h-1 *:origin-[31%]',\n      },\n    },\n    defaultVariants: {\n      size: 'sm',\n    },\n  },\n);\nexport function AnimatedMenuButtonToggleIcon({\n  className,\n  size = 'sm',\n  ...props\n}: React.HTMLAttributes<HTMLDivElement> &\n  VariantProps<typeof buttonIconVariants>) {\n  const { isOpen } = useAnimatedMenuContext();\n  return (\n    <div\n      className={cn(\n        buttonIconVariants({\n          size,\n          className,\n        }),\n      )}\n      {...props}\n    >\n      <motion.span animate={isOpen ? { rotate: 45 } : { rotate: 0 }} />\n      <motion.span animate={isOpen ? { rotate: -45 } : { rotate: 0 }} />\n    </div>\n  );\n}\nexport function AnimatedMenuButtonLabel({\n  closeLabel = 'Menu',\n  openLabel = 'Close',\n  className,\n  ...props\n}: AnimatedMenuButtonLabelProps) {\n  const { isOpen } = useAnimatedMenuContext();\n  return (\n    <div\n      className={cn(\n        'text-sm font-medium overflow-hidden shrink-0 inline-grid grid-rows-1 grid-cols-1',\n        className,\n      )}\n      {...props}\n    >\n      <AnimatePresence>\n        <motion.span\n          key={closeLabel}\n          className=\"will-change-transform col-start-1 row-start-1\"\n          initial={{ y: '0%' }}\n          animate={isOpen ? { y: '-100%' } : { y: '0%' }}\n          exit={{ y: '-100%' }}\n        >\n          {closeLabel}\n        </motion.span>\n        <motion.span\n          key={openLabel}\n          className=\"will-change-transform col-start-1 row-start-1\"\n          initial={{ y: '100%' }}\n          animate={isOpen ? { y: '0%' } : { y: '100%' }}\n          exit={{ y: '100%' }}\n        >\n          {openLabel}\n        </motion.span>\n      </AnimatePresence>\n    </div>\n  );\n}\n\nexport function AnimatedMenuButton({\n  className,\n  children,\n  ...props\n}: React.HTMLAttributes<HTMLButtonElement>) {\n  const { setIsOpen } = useAnimatedMenuContext();\n  const toggleMenu = () => setIsOpen((prevState) => !prevState);\n  return (\n    <button\n      className={cn(\n        'w-20 h-8',\n        'cursor-pointer text-popover-foreground appearance-none relative z-[999] bg-none flex gap-0.5 justify-center items-center',\n        '[&:hover>*]:scale-90 *:transition-transform *:duration-300',\n        className,\n      )}\n      onClick={toggleMenu}\n      {...props}\n    >\n      <MotionConfig\n        transition={{ duration: 0.35, ease: [0.445, 0.05, 0.55, 0.95] }}\n      >\n        {children}\n      </MotionConfig>\n    </button>\n  );\n}\n\nexport function AnimatedMenuList({\n  variants = menuListVariants,\n  className,\n  children,\n  ...props\n}: AnimatedMenuListProps) {\n  const { isOpen } = useAnimatedMenuContext();\n  return (\n    <motion.div\n      className={cn(\n        'absolute right-0 top-0 overflow-hidden bg-popover text-popover-foreground rounded-md z-[800] ',\n        className,\n      )}\n      variants={variants}\n      initial=\"close\"\n      animate={isOpen ? 'open' : 'close'}\n      {...props}\n    >\n      <AnimatePresence>\n        {isOpen && (children as React.ReactNode)}\n      </AnimatePresence>\n    </motion.div>\n  );\n}\n\nexport function AnimatedMenuItem({\n  order = 0,\n  variants = itemVariants,\n  ...props\n}: AnimatedMenuItemProps) {\n  return (\n    <motion.div\n      custom={order}\n      variants={variants}\n      initial=\"initial\"\n      animate=\"enter\"\n      exit=\"exit\"\n      {...props}\n    />\n  );\n}\n\nexport function CloseAnimatedMenu({\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLButtonElement>) {\n  const { setIsOpen } = useAnimatedMenuContext();\n  const closeMenu = () => setIsOpen(false);\n  return (\n    <button\n      className={cn(\n        'appearance-none bg-none outline-none border-none',\n        className,\n      )}\n      onClick={closeMenu}\n      {...props}\n    />\n  );\n}\n",
      "type": "registry:block",
      "target": "components/systaliko-ui/animated-menu.tsx"
    }
  ],
  "type": "registry:block"
}