{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "use-rough", "title": "useRough", "description": "Core Rough.js SVG drawing hook — drawRect, drawLine, drawCircle, drawPath, getOptions, theme-aware.", "dependencies": [ "roughjs" ], "registryDependencies": [ "https://www.bydefaulthuman.fun/r/rough-lib.json" ], "files": [ { "path": "registry/new-york/hooks/use-rough.ts", "content": "\"use client\";\n\nimport { useCallback, useContext, useRef, type RefObject } from \"react\";\nimport rough from \"roughjs\";\nimport type { Options } from \"roughjs/bin/core\";\nimport type { RoughSVG } from \"roughjs/bin/svg\";\nimport {\n CrumbleContext,\n getRoughOptions,\n randomSeed,\n stableSeed,\n type ComponentVariant,\n type CrumbleTheme,\n} from \"@/lib/rough\";\n\ninterface UseRoughProps {\n variant?: ComponentVariant;\n options?: Partial;\n stableId?: string;\n theme?: CrumbleTheme;\n svgRef?: RefObject;\n}\n\nexport function useRough({\n variant = \"border\",\n options,\n stableId,\n theme: themeProp,\n svgRef: externalSvgRef,\n}: UseRoughProps = {}) {\n const internalSvgRef = useRef(null);\n const svgRef = externalSvgRef ?? internalSvgRef;\n const rcRef = useRef(null);\n const lastSvgRef = useRef(null);\n const {\n animateOnHover,\n animateOnMount,\n theme: contextTheme,\n } = useContext(CrumbleContext);\n const theme = themeProp ?? contextTheme;\n\n const getRenderer = useCallback(() => {\n if (!svgRef.current) return null;\n\n if (rcRef.current && lastSvgRef.current === svgRef.current) {\n return rcRef.current;\n }\n\n rcRef.current = rough.svg(svgRef.current);\n lastSvgRef.current = svgRef.current;\n return rcRef.current;\n }, [svgRef]);\n\n const getOptions = useCallback(\n (extra?: Partial) => {\n const resolvedSeed =\n extra?.seed ?? (stableId ? stableSeed(stableId) : randomSeed());\n return getRoughOptions(theme, variant, {\n ...options,\n ...extra,\n seed: resolvedSeed,\n });\n },\n [animateOnHover, options, stableId, theme, variant],\n );\n\n const drawRect = useCallback(\n (\n x: number,\n y: number,\n width: number,\n height: number,\n extra?: Partial,\n ) => {\n const rc = getRenderer();\n if (!rc) return null;\n\n return rc.rectangle(x, y, width, height, getOptions(extra));\n },\n [getOptions, getRenderer],\n );\n\n const drawCircle = useCallback(\n (cx: number, cy: number, diameter: number, extra?: Partial) => {\n const rc = getRenderer();\n if (!rc) return null;\n\n return rc.circle(cx, cy, diameter, getOptions(extra));\n },\n [getOptions, getRenderer],\n );\n\n const drawLine = useCallback(\n (\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n extra?: Partial,\n ) => {\n const rc = getRenderer();\n if (!rc) return null;\n\n return rc.line(x1, y1, x2, y2, getOptions(extra));\n },\n [getOptions, getRenderer],\n );\n\n const drawPath = useCallback(\n (pathData: string, extra?: Partial) => {\n const rc = getRenderer();\n if (!rc) return null;\n\n return rc.path(pathData, getOptions(extra));\n },\n [getOptions, getRenderer],\n );\n\n const drawPolygon = useCallback(\n (points: [number, number][], extra?: Partial) => {\n const rc = getRenderer();\n if (!rc) return null;\n\n return rc.polygon(points, getOptions(extra));\n },\n [getOptions, getRenderer],\n );\n\n const drawEllipse = useCallback(\n (\n cx: number,\n cy: number,\n width: number,\n height: number,\n extra?: Partial,\n ) => {\n const rc = getRenderer();\n if (!rc) return null;\n\n return rc.ellipse(cx, cy, width, height, getOptions(extra));\n },\n [getOptions, getRenderer],\n );\n return {\n animateOnHover,\n drawEllipse,\n drawPolygon,\n animateOnMount,\n drawCircle,\n drawLine,\n drawPath,\n drawRect,\n getOptions,\n rc: rcRef,\n svgRef,\n theme,\n };\n}\n", "type": "registry:hook", "target": "hooks/use-rough.ts" } ], "type": "registry:hook" }