{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "signature",
  "type": "registry:block",
  "title": "Signature",
  "description": "Signature",
  "files": [
    {
      "path": "components/usages/signatureusage.tsx",
      "content": "import { Signature } from \"@/registry/open-source/signature\"\nexport default function SignatureUsage() {\n    return (\n        <div>\n            <Signature\n                text=\"Drive BRand Studio\"\n                fontSize={48}\n                duration={1.5}\n            />\n        </div>\n    )\n}",
      "type": "registry:block",
      "target": "~/example.tsx"
    },
    {
      "path": "components/usages/signatureusage.tsx",
      "content": "import { Signature } from \"@/registry/open-source/signature\"\nexport default function SignatureUsage() {\n    return (\n        <div>\n            <Signature\n                text=\"Drive BRand Studio\"\n                fontSize={48}\n                duration={1.5}\n            />\n        </div>\n    )\n}",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/signature.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useId, useState } from \"react\";\nimport { motion } from \"motion/react\";\nimport opentype from \"opentype.js\";\nimport { cn } from \"@/registry/utilities/cn\";\n\n// Credit:\n// https://www.componentry.fun/docs/components/signature\n\ninterface SignatureProps {\n    /** Text to generate signature for */\n    text?: string;\n    /** Color of the signature path */\n    color?: string;\n    /** Font size of the signature */\n    fontSize?: number;\n    /** Animation duration in seconds */\n    duration?: number;\n    /** Delay before animation starts in seconds */\n    delay?: number;\n    /** Additional CSS classes */\n    className?: string;\n    /** Only animate when in view */\n    inView?: boolean;\n    /** Only animate once */\n    once?: boolean;\n    /** Custom font URL to load */\n    fontUrl?: string;\n}\n\nexport function Signature({\n    text = \"Signature\",\n    color = \"currentColor\",\n    fontSize = 32,\n    duration = 1.5,\n    delay = 0,\n    className,\n    inView = false,\n    once = true,\n    fontUrl,\n}: SignatureProps) {\n    const [paths, setPaths] = useState<string[]>([]);\n    const [width, setWidth] = useState<number>(300);\n    const height = fontSize * 3; // Give plenty of vertical space\n    const horizontalPadding = fontSize * 0.1;\n    const topMargin = fontSize * 1.5; // Shift down\n    const baseline = topMargin;\n    const maskId = `signature-reveal-${useId().replace(/:/g, \"\")}`;\n\n    useEffect(() => {\n        async function load() {\n            try {\n                let font;\n                const fontPaths = fontUrl\n                    ? [fontUrl]\n                    : [\n                        \"/LastoriaBoldRegular.otf\",\n                        \"./LastoriaBoldRegular.otf\",\n                        \"https://www.componentry.fun/LastoriaBoldRegular.otf\",\n                    ];\n\n                for (const path of fontPaths) {\n                    try {\n                        font = await opentype.load(path as string);\n                        break;\n                    } catch {\n                        // Try next path\n                    }\n                }\n\n                if (!font) {\n                    throw new Error(\"Font could not be loaded from any path\");\n                }\n\n                let x = horizontalPadding;\n                const newPaths: string[] = [];\n\n                for (const char of text) {\n                    const glyph = font.charToGlyph(char);\n                    const path = glyph.getPath(x, baseline, fontSize);\n                    newPaths.push(path.toPathData(3));\n\n                    const advanceWidth = glyph.advanceWidth ?? font.unitsPerEm;\n                    x += advanceWidth * (fontSize / font.unitsPerEm);\n                }\n\n                setPaths(newPaths);\n                setWidth(x + horizontalPadding);\n            } catch (error) {\n                console.error(\"Signature component font load error:\", error);\n                setPaths([]);\n                setWidth(text.length * fontSize * 0.6);\n            }\n        }\n\n        load();\n    }, [text, fontSize, baseline, horizontalPadding, fontUrl]);\n\n    const variants = {\n        hidden: { pathLength: 0, opacity: 0 },\n        visible: { pathLength: 1, opacity: 1 },\n    };\n\n    return (\n        <motion.svg\n            key={paths.length}\n            width={width}\n            height={height}\n            viewBox={`0 0 ${width} ${height}`}\n            fill=\"none\"\n            className={cn(\"text-foreground overflow-visible\", className)}\n            initial=\"hidden\"\n            whileInView={inView ? \"visible\" : undefined}\n            animate={inView ? undefined : \"visible\"}\n            viewport={{ once }}\n        >\n            <defs>\n                <mask id={maskId} maskUnits=\"userSpaceOnUse\">\n                    {paths.map((d, i) => (\n                        <motion.path\n                            key={i}\n                            d={d}\n                            stroke=\"white\"\n                            strokeWidth={fontSize * 0.22}\n                            fill=\"none\"\n                            variants={variants}\n                            transition={{\n                                pathLength: {\n                                    delay: delay + i * 0.2,\n                                    duration,\n                                    ease: \"easeInOut\",\n                                },\n                                opacity: {\n                                    delay: delay + i * 0.2 + 0.01,\n                                    duration: 0.01,\n                                },\n                            }}\n                            vectorEffect=\"non-scaling-stroke\"\n                            strokeLinecap=\"round\"\n                            strokeLinejoin=\"round\"\n                        />\n                    ))}\n                </mask>\n            </defs>\n\n            {paths.map((d, i) => (\n                <motion.path\n                    key={i}\n                    d={d}\n                    stroke={color}\n                    strokeWidth={2}\n                    fill=\"none\"\n                    variants={variants}\n                    transition={{\n                        pathLength: {\n                            delay: delay + i * 0.2,\n                            duration,\n                            ease: \"easeInOut\",\n                        },\n                        opacity: {\n                            delay: delay + i * 0.2 + 0.01,\n                            duration: 0.01,\n                        },\n                    }}\n                    vectorEffect=\"non-scaling-stroke\"\n                    strokeLinecap=\"butt\"\n                    strokeLinejoin=\"round\"\n                />\n            ))}\n\n            <g mask={`url(#${maskId})`}>\n                {paths.map((d, i) => <path key={i} d={d} fill={color} />)}\n            </g>\n        </motion.svg>\n    );\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/utilities/cn.ts",
      "content": "import { ClassValue, clsx } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n\treturn twMerge(clsx(inputs));\r\n}\r\n",
      "type": "registry:ui"
    }
  ]
}