Todos os componentes

Confetti

Confetti é um componente de efeito para React e Tailwind CSS, da biblioteca Magic UI, com licença MIT. Copia e cola no teu projeto.

Magic UI MIT effects

O que é

Confetti é um componente de efeito para React e Tailwind CSS, da biblioteca Magic UI, com licença MIT. Copia e cola no teu projeto.

Como usar

Abre o componente no catálogo, carrega em copiar, e cola no teu projeto. O prompt copiado leva o código e as regras para o teu agente o reproduzir sem alterar nada.

Abrir no catálogo

Cinco cópias grátis por mês. Sem cartão.

Precisa de

npm i canvas-confetti @types/canvas-confetti

Licença

Este componente vem de Magic UI e é redistribuído sob a licença MIT, que permite uso comercial. O aviso de copyright viaja com o código.

Confetti

registry/magicui/confetti.tsx
"use client"

import type { ReactNode } from "react"
import React, {
  createContext,
  forwardRef,
  useCallback,
  useEffect,
  useImperativeHandle,
  useMemo,
  useRef,
} from "react"
import type {
  GlobalOptions as ConfettiGlobalOptions,
  CreateTypes as ConfettiInstance,
  Options as ConfettiOptions,
} from "canvas-confetti"
import confetti from "canvas-confetti"

import { Button } from "@/components/ui/button"

export type ConfettiRef = {
  fire: (options?: ConfettiOptions) => Promise<void> | void
}

type Props = React.ComponentPropsWithRef<"canvas"> & {
  options?: ConfettiOptions
  globalOptions?: ConfettiGlobalOptions
  manualstart?: boolean
  children?: ReactNode
}

const ConfettiContext = createContext<ConfettiRef | null>(null)

const ConfettiComponent = forwardRef<ConfettiRef, Props>((props, ref) => {
  const {
    options,
    globalOptions = { resize: true, useWorker: true },
    manualstart = false,
    children,
    className,
    ...rest
  } = props

  const canvasNodeRef = useRef<HTMLCanvasElement | null>(null)
  const instanceRef = useRef<ConfettiInstance | null>(null)
  const optionsRef = useRef(options)
  const globalOptionsRef = useRef(globalOptions)

  useEffect(() => {
    optionsRef.current = options
  }, [options])

  useEffect(() => {
    globalOptionsRef.current = globalOptions
  }, [globalOptions])

  useEffect(() => {
    if (canvasNodeRef.current && !instanceRef.current) {
      instanceRef.current = confetti.create(canvasNodeRef.current, {
        resize: true,
        useWorker: true,
        ...globalOptionsRef.current,
      })
    }

    return () => {
      instanceRef.current?.reset()
      instanceRef.current = null
    }
  }, [])

  const fire = useCallback(async (opts: ConfettiOptions = {}) => {
    try {
      await instanceRef.current?.({
        ...optionsRef.current,
        ...opts,
      })
    } catch (error) {
      console.error("Confetti error:", error)
    }
  }, [])

  const api = useMemo<ConfettiRef>(() => ({ fire }), [fire])

  useImperativeHandle(ref, () => api, [api])

  useEffect(() => {
    if (!manualstart) {
      void fire()
    }
  }, [manualstart, fire])

  return (
    <ConfettiContext.Provider value={api}>
      <canvas ref={canvasNodeRef} className={className} {...rest} />
      {children}
    </ConfettiContext.Provider>
  )
})

ConfettiComponent.displayName = "Confetti"

export const Confetti = ConfettiComponent

export interface ConfettiButtonProps extends React.ComponentPropsWithoutRef<
  typeof Button
> {
  options?: ConfettiOptions &
    ConfettiGlobalOptions & { canvas?: HTMLCanvasElement }
}

export const ConfettiButton = forwardRef<
  HTMLButtonElement,
  ConfettiButtonProps
>(({ options, children, onClick, ...props }, ref) => {
  const handleClick: ConfettiButtonProps["onClick"] = async (event) => {
    try {
      onClick?.(event)
      if (event?.defaultPrevented) return

      const target = event?.currentTarget
      if (target && "getBoundingClientRect" in target) {
        const rect = target.getBoundingClientRect()
        const origin = {
          x: (rect.left + rect.width / 2) / window.innerWidth,
          y: (rect.top + rect.height / 2) / window.innerHeight,
        }

        await confetti({
          zIndex: 9999,
          ...options,
          origin,
        })
      }
    } catch (error) {
      console.error("Confetti button error:", error)
    }
  }

  return (
    <Button ref={ref} type="button" onClick={handleClick} {...props}>
      {children}
    </Button>
  )
})

ConfettiButton.displayName = "ConfettiButton"

Componentes parecidos