{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "flip",
  "dependencies": [
    "class-variance-authority",
    "motion"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "src/components/watermelon-ui/flip.tsx",
      "content": "'use client'\n\nimport * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '@/lib/utils';\nimport { isMotionComponent, motion, type HTMLMotionProps, type Variant } from 'motion/react';\n\n\n\ntype FlipButtonContextType = VariantProps<typeof buttonVariants>;\n\nconst [FlipButtonProvider, useFlipButton] =\n  getStrictContext<FlipButtonContextType>('FlipButtonContext');\n\ntype FlipButtonProps = FlipButtonPrimitiveProps &\n  VariantProps<typeof buttonVariants>;\n\nfunction FlipButton({ variant, size, ...props }: FlipButtonProps) {\n  return (\n    <FlipButtonProvider value={{ variant, size }}>\n      <FlipButtonPrimitive {...props} />\n    </FlipButtonProvider>\n  );\n}\n\ntype FlipButtonFrontProps = FlipButtonPrimitiveProps &\n  VariantProps<typeof buttonVariants>;\n\nfunction FlipButtonFront({\n  variant,\n  size,\n  className,\n  ...props\n}: FlipButtonFrontProps) {\n  const { variant: buttonVariant, size: buttonSize } = useFlipButton();\n  return (\n    <FlipButtonFrontPrimitive\n      className={cn(\n        buttonVariants({\n          variant: variant ?? buttonVariant,\n          size: size ?? buttonSize,\n          className,\n        }),\n      )}\n      {...props}\n    />\n  );\n}\n\ntype FlipButtonBackProps = FlipButtonPrimitiveProps &\n  VariantProps<typeof buttonVariants>;\n\nfunction FlipButtonBack({\n  variant,\n  size,\n  className,\n  ...props\n}: FlipButtonBackProps) {\n  const { variant: buttonVariant, size: buttonSize } = useFlipButton();\n  return (\n    <FlipButtonBackPrimitive\n      className={cn(\n        buttonVariants({\n          variant: variant ?? buttonVariant,\n          size: size ?? buttonSize,\n          className,\n        }),\n      )}\n      {...props}\n    />\n  );\n}\n\nexport {\n  FlipButton,\n  FlipButtonFront,\n  FlipButtonBack,\n  type FlipButtonProps,\n  type FlipButtonFrontProps,\n  type FlipButtonBackProps,\n};\n\n\nconst buildVariant = ({\n  opacity,\n  rotation,\n  offset,\n  isVertical,\n  rotateAxis,\n}: {\n  opacity: number;\n  rotation: number;\n  offset: string | null;\n  isVertical: boolean;\n  rotateAxis: string;\n}): Variant => ({\n  opacity,\n  [rotateAxis]: rotation,\n  ...(isVertical && offset !== null ? { y: offset } : {}),\n  ...(!isVertical && offset !== null ? { x: offset } : {}),\n});\n\ntype FlipDirection = 'top' | 'bottom' | 'left' | 'right';\n\ntype FlipButtonContextTypePrimitive = {\n  from: FlipDirection;\n  isVertical: boolean;\n  rotateAxis: string;\n};\n\nconst [FlipButtonProviderPrimitive, useFlipButtonPrimitive] =\n  getStrictContext<FlipButtonContextTypePrimitive>('FlipButtonContext');\n\ntype FlipButtonPrimitiveProps = WithAsChild<\n  HTMLMotionProps<'button'> & {\n    from?: FlipDirection;\n    tapScale?: number;\n  }\n>;\n\nfunction FlipButtonPrimitive({\n  from = 'top',\n  tapScale = 0.95,\n  asChild = false,\n  style,\n  ...props\n}: FlipButtonPrimitiveProps) {\n  const isVertical = from === 'top' || from === 'bottom';\n  const rotateAxis = isVertical ? 'rotateX' : 'rotateY';\n\n  const Component = asChild ? Slot : motion.button;\n\n  return (\n    <FlipButtonProviderPrimitive value={{ from, isVertical, rotateAxis }}>\n      <Component\n        data-slot=\"flip-button\"\n        initial=\"initial\"\n        whileHover=\"hover\"\n        whileTap={{ scale: tapScale }}\n        style={{\n          display: 'inline-grid',\n          placeItems: 'center',\n          perspective: '1000px',\n          ...style,\n        }}\n        {...props}\n      />\n    </FlipButtonProviderPrimitive>\n  );\n}\n\ntype FlipButtonFacePrimitiveProps = WithAsChild<HTMLMotionProps<'span'>>;\n\nfunction FlipButtonFrontPrimitive({\n  transition = { type: 'spring', stiffness: 280, damping: 20 },\n  asChild = false,\n  style,\n  ...props\n}: FlipButtonFacePrimitiveProps) {\n  const { from, isVertical, rotateAxis } = useFlipButtonPrimitive();\n\n  const frontOffset = from === 'top' || from === 'left' ? '50%' : '-50%';\n\n  const frontVariants = {\n    initial: buildVariant({\n      opacity: 1,\n      rotation: 0,\n      offset: '0%',\n      isVertical,\n      rotateAxis,\n    }),\n    hover: buildVariant({\n      opacity: 0,\n      rotation: 90,\n      offset: frontOffset,\n      isVertical,\n      rotateAxis,\n    }),\n  };\n\n  const Component = asChild ? Slot : motion.span;\n\n  return (\n    <Component\n      data-slot=\"flip-button-front\"\n      variants={frontVariants}\n      transition={transition}\n      style={{\n        gridArea: '1 / 1',\n        display: 'inline-flex',\n        alignItems: 'center',\n        justifyContent: 'center',\n        ...style,\n      }}\n      {...props}\n    />\n  );\n}\n\nfunction FlipButtonBackPrimitive({\n  transition = { type: 'spring', stiffness: 280, damping: 20 },\n  asChild = false,\n  style,\n  ...props\n}: FlipButtonFacePrimitiveProps) {\n  const { from, isVertical, rotateAxis } = useFlipButtonPrimitive();\n\n  const backOffset = from === 'top' || from === 'left' ? '-50%' : '50%';\n\n  const backVariants = {\n    initial: buildVariant({\n      opacity: 0,\n      rotation: 90,\n      offset: backOffset,\n      isVertical,\n      rotateAxis,\n    }),\n    hover: buildVariant({\n      opacity: 1,\n      rotation: 0,\n      offset: '0%',\n      isVertical,\n      rotateAxis,\n    }),\n  };\n\n  const Component = asChild ? Slot : motion.span;\n\n  return (\n    <Component\n      data-slot=\"flip-button-back\"\n      variants={backVariants}\n      transition={transition}\n      style={{\n        gridArea: '1 / 1',\n        display: 'inline-flex',\n        alignItems: 'center',\n        justifyContent: 'center',\n        ...style,\n      }}\n      {...props}\n    />\n  );\n}\n\n\n\nconst buttonVariants = cva(\n  \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[box-shadow,_color,_background-color,_border-color,_outline-color,_text-decoration-color,_fill,_stroke] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n  {\n    variants: {\n      variant: {\n        default:\n          'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90',\n        accent: 'bg-accent text-accent-foreground shadow-xs hover:bg-accent/90',\n        destructive:\n          'bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',\n        outline:\n          'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',\n        secondary:\n          'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',\n        ghost:\n          'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',\n        link: 'text-primary underline-offset-4 hover:underline',\n      },\n      size: {\n        default: 'h-9 px-4 py-2 has-[>svg]:px-3',\n        sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',\n        lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',\n        icon: 'size-9',\n        'icon-sm': 'size-8 rounded-md',\n        'icon-lg': 'size-10 rounded-md',\n      },\n    },\n    defaultVariants: {\n      variant: 'default',\n      size: 'default',\n    },\n  },\n);\n\n\nfunction getStrictContext<T>(\n  name?: string,\n): readonly [\n  ({\n    value,\n    children,\n  }: {\n    value: T;\n    children?: React.ReactNode;\n  }) => React.JSX.Element,\n  () => T,\n] {\n  const Context = React.createContext<T | undefined>(undefined);\n\n  const Provider = ({\n    value,\n    children,\n  }: {\n    value: T;\n    children?: React.ReactNode;\n  }) => <Context.Provider value={value}>{children}</Context.Provider>;\n\n  const useSafeContext = () => {\n    const ctx = React.useContext(Context);\n    if (ctx === undefined) {\n      throw new Error(`useContext must be used within ${name ?? 'a Provider'}`);\n    }\n    return ctx;\n  };\n\n  return [Provider, useSafeContext] as const;\n}\n\nexport { getStrictContext };\n\ntype AnyProps = Record<string, unknown>;\n\ntype DOMMotionProps<T extends HTMLElement = HTMLElement> = Omit<\n  HTMLMotionProps<keyof HTMLElementTagNameMap>,\n  'ref'\n> & { ref?: React.Ref<T> };\n\ntype WithAsChild<Base extends object> =\n  | (Base & { asChild: true; children: React.ReactElement })\n  | (Base & { asChild?: false | undefined });\n\ntype SlotProps<T extends HTMLElement = HTMLElement> = {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  children?: any;\n} & DOMMotionProps<T>;\n\nfunction mergeRefs<T>(\n  ...refs: (React.Ref<T> | undefined)[]\n): React.RefCallback<T> {\n  return (node) => {\n    refs.forEach((ref) => {\n      if (!ref) return;\n      if (typeof ref === 'function') {\n        ref(node);\n      } else {\n        (ref as React.RefObject<T | null>).current = node;\n      }\n    });\n  };\n}\n\nfunction mergeProps<T extends HTMLElement>(\n  childProps: AnyProps,\n  slotProps: DOMMotionProps<T>,\n): AnyProps {\n  const merged: AnyProps = { ...childProps, ...slotProps };\n\n  if (childProps.className || slotProps.className) {\n    merged.className = cn(\n      childProps.className as string,\n      slotProps.className as string,\n    );\n  }\n\n  if (childProps.style || slotProps.style) {\n    merged.style = {\n      ...(childProps.style as React.CSSProperties),\n      ...(slotProps.style as React.CSSProperties),\n    };\n  }\n\n  return merged;\n}\n\nfunction Slot<T extends HTMLElement = HTMLElement>({\n  children,\n  ref,\n  ...props\n}: SlotProps<T>) {\n  const isAlreadyMotion =\n    typeof children.type === 'object' &&\n    children.type !== null &&\n    isMotionComponent(children.type);\n\n  const Base = React.useMemo(\n    () =>\n      isAlreadyMotion\n        ? (children.type as React.ElementType)\n        : motion.create(children.type as React.ElementType),\n    [isAlreadyMotion, children.type],\n  );\n\n  if (!React.isValidElement(children)) return null;\n\n  const { ref: childRef, ...childProps } = children.props as AnyProps;\n\n  const mergedProps = mergeProps(childProps, props);\n\n  return (\n    // eslint-disable-next-line react-hooks/static-components\n    <Base {...mergedProps} ref={mergeRefs(childRef as React.Ref<T>, ref)} />\n  );\n}\n\nexport {\n  Slot,\n  type SlotProps,\n  type WithAsChild,\n  type DOMMotionProps,\n  type AnyProps,\n};\n",
      "type": "registry:ui",
      "target": "components/ui/flip.tsx"
    }
  ],
  "type": "registry:ui"
}
