{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "confetti", "type": "registry:ui", "title": "Confetti", "description": "Confetti animations are best used to delight your users when something special happens", "dependencies": [ "canvas-confetti", "@types/canvas-confetti" ], "registryDependencies": [ "button" ], "files": [ { "path": "registry/magicui/confetti.tsx", "content": ""use client"\n\nimport type { ReactNode } from "react"\nimport React, {\n createContext,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n} from "react"\nimport type {\n GlobalOptions as ConfettiGlobalOptions,\n CreateTypes as ConfettiInstance,\n Options as ConfettiOptions,\n} from "canvas-confetti"\nimport confetti from "canvas-confetti"\n\nimport { Button } from "@/components/ui/button"\n\ntype Api = {\n fire: (options?: ConfettiOptions) => void\n}\ntype Props = React.ComponentPropsWithRef("canvas") & {\n options?: ConfettiOptions\n globalOptions?: ConfettiGlobalOptions\n manualstart?: boolean\n children?: ReactNode\n}\n\nexport type ConfettiRef = Api | null\n\nconst ConfettiContext = createContext({} as Api)\n\n// Define component first\nconst ConfettiComponent = forwardRef((props, ref) => {\n const {\n options,\n globalOptions = { resize: true, useWorker: true },\n manualstart = false,\n children,\n ...rest\n } = props\n const instanceRef = useRef(null)\n\n const canvasRef = useCallback(\n (node: HTMLCanvasElement) => {\n if (node !== null) {\n if (instanceRef.current) return\n instanceRef.current = confetti.create(node, {\n ...globalOptions,\n resize: true,\n })\n } else {\n if (instanceRef.current) {\n instanceRef.current.reset()\n instanceRef.current = null\n }\n }\n },\n [globalOptions]\n )\n\n const fire = useCallback(\n async (opts = {}) => {\n try {\n await instanceRef.current?.({ ...options, ...opts })\n } catch (error) {\n console.error("Confetti error:", error)\n }\n },\n [options]\n )\n\n const api = useMemo(\n () => ({\n fire,\n }),\n [fire]\n )\n\n useImperativeHandle(ref, () => api, [api])\n\n useEffect(() => {\n if (!manualstart) {\n ;(async () => {\n try {\n await fire()\n } catch (error) {\n console.error("Confetti effect error:", error)\n }\n })()\n }\n }, [manualstart, fire])\n\n return (\n \n \n {children}\n \n )\n})\n\n// Set display name immediately\nConfettiComponent.displayName = "Confetti"\n\n// Export as Confetti\nexport const Confetti = ConfettiComponent\n\ninterface ConfettiButtonProps extends React.ComponentProps("button") {\n options?: ConfettiOptions &\n ConfettiGlobalOptions & { canvas?: HTMLCanvasElement }\n}\n\nconst ConfettiButtonComponent = ({\n options,\n children,\n ...props\n}: ConfettiButtonProps) => {\n const handleClick = async (event: React.MouseEvent) => {\n try {\n const rect = event.currentTarget.getBoundingClientRect()\n const x = rect.left + rect.width / 2\n const y = rect.top + rect.height / 2\n await confetti({\n ...options,\n origin: {\n x: x / window.innerWidth,\n y: y / window.innerHeight,\n },\n })\n } catch (error) {\n console.error("Confetti button error:", error)\n }\n }\n\n return (\n \n {children}\n \n )\n}\n\nConfettiButtonComponent.displayName = "ConfettiButton"\n\nexport const ConfettiButton = ConfettiButtonComponent\n" } ] }