-
Notifications
You must be signed in to change notification settings - Fork 125
/
Copy pathban.json
21 lines (21 loc) · 3.64 KB
/
ban.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"name": "ban",
"type": "registry:ui",
"registryDependencies": [],
"dependencies": [
"motion"
],
"devDependencies": [],
"tailwind": {},
"cssVars": {
"light": {},
"dark": {}
},
"files": [
{
"path": "ban.tsx",
"content": "'use client';\n\nimport type { Variants } from 'motion/react';\nimport { motion, useAnimation } from 'motion/react';\nimport type { HTMLAttributes } from 'react';\nimport { forwardRef, useCallback, useImperativeHandle, useRef } from 'react';\nimport { cn } from '@/lib/utils';\n\nexport interface BanIconHandle {\n startAnimation: () => void;\n stopAnimation: () => void;\n}\n\ninterface BanIconProps extends HTMLAttributes<HTMLDivElement> {\n size?: number;\n}\n\nconst circleVariants: Variants = {\n normal: {\n opacity: 1,\n pathLength: 1,\n transition: {\n duration: 0.3,\n opacity: { duration: 0.1 },\n },\n },\n animate: {\n opacity: [0, 1],\n pathLength: [0, 1],\n transition: {\n duration: 0.4,\n opacity: { duration: 0.1 },\n },\n },\n};\n\nconst lineVariants: Variants = {\n normal: {\n opacity: 1,\n pathLength: 1,\n transition: {\n duration: 0.3,\n opacity: { duration: 0.1 },\n },\n },\n slash: () => ({\n opacity: [0, 1],\n pathLength: [0, 1],\n transition: {\n duration: 0.4,\n opacity: { duration: 0.1 },\n },\n }),\n};\n\nconst BanIcon = forwardRef<BanIconHandle, BanIconProps>(\n ({ onMouseEnter, onMouseLeave, className, size = 28, ...props }, ref) => {\n const controls = useAnimation();\n const isControlledRef = useRef(false);\n\n useImperativeHandle(ref, () => {\n isControlledRef.current = true;\n\n return {\n startAnimation: () => {\n controls.start('animate');\n controls.start('slash', { delay: 0.5 });\n },\n stopAnimation: () => controls.start('normal'),\n };\n });\n\n const handleMouseEnter = useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n if (!isControlledRef.current) {\n controls.start('animate');\n controls.start('slash', { delay: 0.5 });\n } else {\n onMouseEnter?.(e);\n }\n },\n [controls, onMouseEnter]\n );\n\n const handleMouseLeave = useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n if (!isControlledRef.current) {\n controls.start('normal');\n } else {\n onMouseLeave?.(e);\n }\n },\n [controls, onMouseLeave]\n );\n\n return (\n <div\n className={cn(\n `cursor-pointer select-none p-2 hover:bg-accent rounded-md transition-colors duration-200 flex items-center justify-center`,\n className\n )}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n {...props}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <motion.circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n variants={circleVariants}\n initial=\"normal\"\n animate={controls}\n />\n <motion.path\n d=\"m4.9 4.9 14.2 14.2\"\n variants={lineVariants}\n initial=\"normal\"\n animate={controls}\n />\n </svg>\n </div>\n );\n }\n);\n\nBanIcon.displayName = 'BanIcon';\n\nexport { BanIcon };\n",
"type": "registry:ui"
}
]
}