{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"motion-link","type":"registry:block","title":"Motion link","description":"Exclusive to Next.js. A reusable component that extends the <Link/> component from \"next/link\" to power interactive animations using motion.dev. It includes three predefined variants: <MotionLinkUnderline/>, <MotionLinkSlideText/>, and <MotionLinkWithIcon/>, while the base <MotionLink/> provides full flexibility to define custom animations with MotionProps like whileFocus, whileHover, and whileInView.","dependencies":["motion"],"files":[{"path":"registry/100xui/blocks/motion-link/components/motion-link.tsx","content":"\"use client\";\n\nimport React from \"react\";\nimport Link, { type LinkProps } from \"next/link\";\nimport { motion, stagger, MotionConfig, type MotionProps } from \"motion/react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst MLink = motion.create(Link);\n\ntype CombinedAnchorProps = Omit<\n  React.AnchorHTMLAttributes<HTMLAnchorElement>,\n  keyof LinkProps | \"href\"\n>;\n\nexport type MotionLinkBaseProps = LinkProps & MotionProps & CombinedAnchorProps;\nexport function MotionLink(props: MotionLinkBaseProps) {\n  return <MLink {...props} />;\n}\n\nexport interface MotionLinkUnderlineProps extends MotionLinkBaseProps {\n  underlineColor?: React.CSSProperties[\"background\"];\n  underlineHeight?: React.CSSProperties[\"height\"];\n  startDirection?: \"left\" | \"right\";\n  endDirection?: \"left\" | \"right\";\n}\nexport function MotionLinkUnderline({\n  className,\n  children,\n  underlineColor = \"var(--color-foreground)\",\n  underlineHeight = \"2px\",\n  startDirection = \"left\",\n  endDirection = \"right\",\n  ...rest\n}: MotionLinkUnderlineProps) {\n  const isStartDirectionLeft = startDirection === \"left\";\n  const isEndDirectionRight = endDirection === \"right\";\n\n  const underlineActiveStyles = {\n    width: \"100%\",\n    ...(isStartDirectionLeft\n      ? { left: \"0px\", right: \"auto\" }\n      : { left: \"auto\", right: \"0px\" }),\n  };\n\n  return (\n    <MotionLink\n      initial=\"initial\"\n      whileFocus=\"whileFocus\"\n      whileHover=\"whileHover\"\n      className={cn(\n        \"!relative w-fit !text-nowrap text-inherit focus-visible:!outline-0\",\n        className,\n      )}\n      {...rest}\n    >\n      {children}\n      <motion.div\n        style={{\n          height: underlineHeight,\n          background: underlineColor,\n        }}\n        className=\"absolute bottom-0\"\n        variants={{\n          initial: {\n            width: \"0%\",\n            ...(isEndDirectionRight\n              ? { left: \"auto\", right: \"0px\" }\n              : { left: \"0px\", right: \"auto\" }),\n          },\n          whileHover: underlineActiveStyles,\n          whileFocus: underlineActiveStyles,\n        }}\n        transition={{\n          left: { duration: 0 },\n          right: { duration: 0 },\n          default: { ease: \"easeInOut\" },\n        }}\n      />\n    </MotionLink>\n  );\n}\n\nexport interface MotionLinkSlideTextProps extends MotionLinkBaseProps {\n  children: string;\n}\n\nexport function MotionLinkSlideText({\n  children,\n  className,\n  ...rest\n}: MotionLinkSlideTextProps) {\n  const characters = children.split(\"\");\n  const staggerDelay = { transition: { delayChildren: stagger(0.02) } };\n\n  return (\n    <MotionLink\n      initial=\"initial\"\n      whileHover=\"whileHover\"\n      whileFocus=\"whileFocus\"\n      className={cn(\n        \"inline-block text-inherit\",\n        \"!relative focus-visible:!outline-none\",\n        className,\n      )}\n      {...rest}\n    >\n      <MotionConfig transition={{ ease: \"easeInOut\" }}>\n        <motion.div\n          aria-hidden\n          className=\"relative z-20 flex text-nowrap whitespace-pre\"\n          variants={{\n            whileHover: staggerDelay,\n            whileFocus: staggerDelay,\n          }}\n        >\n          {characters.map((char, idx) => (\n            <motion.span\n              key={`char-visible-[${idx}]`}\n              variants={{\n                initial: { scaleY: 1 },\n                whileHover: { scaleY: 0 },\n                whileFocus: { scaleY: 0 },\n              }}\n              className=\"origin-top\"\n            >\n              {char}\n            </motion.span>\n          ))}\n        </motion.div>\n\n        <motion.div\n          aria-hidden\n          variants={{\n            whileHover: staggerDelay,\n            whileFocus: staggerDelay,\n          }}\n          className=\"absolute inset-0 z-10 flex text-nowrap whitespace-pre\"\n        >\n          {characters.map((char, idx) => (\n            <motion.span\n              key={`char-hidden-[${idx}]`}\n              variants={{\n                initial: { scaleY: 0 },\n                whileHover: { scaleY: 1 },\n                whileFocus: { scaleY: 1 },\n              }}\n              className=\"origin-bottom\"\n            >\n              {char}\n            </motion.span>\n          ))}\n        </motion.div>\n      </MotionConfig>\n      <span className=\"sr-only\">{children}</span>\n    </MotionLink>\n  );\n}\nexport interface MotionLinkWithIconProps extends MotionLinkBaseProps {\n  icon: React.ReactNode;\n  iconWidth: React.CSSProperties[\"width\"];\n  gap?: React.CSSProperties[\"gap\"];\n}\n\nexport function MotionLinkWithIcon({\n  icon,\n  iconWidth,\n  gap = \"var(--spacing)\",\n  className,\n  children,\n  ...rest\n}: MotionLinkWithIconProps) {\n  return (\n    <MotionLink\n      initial=\"initial\"\n      whileHover=\"whileHover\"\n      whileFocus=\"whileFocus\"\n      className={cn(\n        \"inline-block !overflow-hidden text-inherit focus-visible:!outline-none\",\n        className,\n      )}\n      {...rest}\n    >\n      <motion.div\n        variants={{\n          initial: { x: `calc((${iconWidth} + ${gap}) * -1)` },\n          whileHover: { x: \"0px\" },\n          whileFocus: { x: \"0px\" },\n        }}\n        transition={{ ease: \"easeInOut\" }}\n        className=\"flex items-center\"\n        style={{ gap }}\n      >\n        {icon}\n        {children}\n      </motion.div>\n    </MotionLink>\n  );\n}\n","type":"registry:component"}]}