UNPKG

v12-ui

Version:

A React component library with a focus on utility-first design and accessibility.

122 lines (121 loc) 4.85 kB
import { jsx as v } from "react/jsx-runtime"; import { useRef as g, useEffect as u } from "react"; import { useDataTheme as m } from "../Hooks/useDataTheme.js"; class y { canvas; ctx; particles = []; mouse = null; animationId = null; dpr; config; constructor(t, i) { this.canvas = t; const e = t.getContext("2d"); if (!e) throw new Error("No se pudo obtener el contexto 2D del canvas"); this.ctx = e, this.dpr = window.devicePixelRatio || 1, this.config = i, this.setupCanvas(), this.generateParticles(), this.animate = this.animate.bind(this), this.animate(); } setupCanvas() { const t = this.canvas.getBoundingClientRect(); this.canvas.width = t.width * this.dpr, this.canvas.height = t.height * this.dpr, this.canvas.style.width = `${t.width}px`, this.canvas.style.height = `${t.height}px`, this.ctx.scale(this.dpr, this.dpr), this.ctx.imageSmoothingEnabled = !0, this.ctx.imageSmoothingQuality && (this.ctx.imageSmoothingQuality = "high"); } createTextMask() { return this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height), this.ctx.font = `bold ${this.config.fontSize || 80}px ${this.config.fontFamily || "sans-serif"}`, this.ctx.textAlign = "center", this.ctx.textBaseline = "middle", this.ctx.fillStyle = `${this.config.textColor || "#fff"}`, this.ctx.fillText(this.config.text, this.canvas.width / 2, this.canvas.height / 2), this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height); } extractPositions(t) { const i = [], e = t.width * t.height, n = Math.max(1, Math.floor(Math.sqrt(e / this.config.particles))); for (let h = 0; h < t.height; h += n) for (let s = 0; s < t.width; s += n) { const a = (h * t.width + s) * 4; t.data[a + 3] > 128 && i.push({ x: s, y: h }); } return i; } generateParticles() { const t = this.createTextMask(), e = this.extractPositions(t).sort(() => Math.random() - 0.5); this.particles = e.slice(0, Math.min(this.config.particles, e.length)).map((n) => ({ tx: n.x, ty: n.y, x: Math.random() * this.canvas.width, y: Math.random() * this.canvas.height, vx: 0, vy: 0 })); } updateParticle(t) { const i = t.tx - t.x, e = t.ty - t.y; if (t.vx += i * this.config.returnSpeed, t.vy += e * this.config.returnSpeed, t.vx *= this.config.friction, t.vy *= this.config.friction, t.x += t.vx, t.y += t.vy, this.mouse) { const n = this.mouse.x - t.x, h = this.mouse.y - t.y, s = Math.hypot(n, h); if (s < this.config.repulsion && s > 0) { const a = (this.config.repulsion - s) / this.config.repulsion, o = 10; t.vx -= n / s * a * o, t.vy -= h / s * a * o; } t.vx += i * this.config.returnSpeed * 0.5, t.vy += e * this.config.returnSpeed * 0.5; } else t.vx += i * this.config.returnSpeed, t.vy += e * this.config.returnSpeed; } drawParticles() { this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); for (const t of this.particles) this.updateParticle(t), this.ctx.fillStyle = `${this.config.textColor || "#fff"}`, this.ctx.beginPath(), this.ctx.arc(t.x, t.y, this.config.dotSize, 0, Math.PI * 2), this.ctx.fill(); } handleMouseMove = (t) => { const i = this.canvas.getBoundingClientRect(); this.mouse = { x: (t.clientX - i.left) * (this.canvas.width / i.width), y: (t.clientY - i.top) * (this.canvas.height / i.height) }; }; handleMouseLeave = () => { this.mouse = null; }; animate() { this.drawParticles(), this.canvas.addEventListener("mousemove", this.handleMouseMove), this.canvas.addEventListener("mouseleave", this.handleMouseLeave), this.animationId = requestAnimationFrame(this.animate); } destroy() { this.canvas.removeEventListener("mousemove", this.handleMouseMove), this.canvas.removeEventListener("mouseleave", this.handleMouseLeave), this.animationId && cancelAnimationFrame(this.animationId); } } function P({ text: c = "Magic Text", particles: t = 1e5, dotSize: i = 1.5, repulsion: e = 100, friction: n = 0.82, returnSpeed: h = 0.01, fontFamily: s = "sans-serif", fontSize: a = 80, textColor: o }) { const { theme: r } = m(), l = o || (r === "dark" ? "#fff" : "#000"); console.log("Theme:", r, "Color detected:", l); const d = g(null); return u(() => { const f = d.current; if (!f) return; const x = new y(f, { text: c, particles: t, dotSize: i, repulsion: e, friction: n, returnSpeed: h, fontFamily: s, fontSize: a, textColor: l }); return () => { x && x.destroy(); }; }, [c, t, i, e, n, h, s, a, r, o]), /* @__PURE__ */ v( "canvas", { ref: d, className: "block mx-auto", style: { width: "100%", height: "100%" } } ); } export { P as MagicText };