1"use client";
2
3import * as React from "react";
4import { cn } from "@/lib/utils";
5
6export interface GlowTextAreaProps
7 extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
8 error?: boolean;
9}
10
11const GlowTextArea = React.forwardRef<HTMLTextAreaElement, GlowTextAreaProps>(
12 ({ className, error, onFocus, onBlur, ...props }, ref) => {
13 const [focused, setFocused] = React.useState(false);
14 const containerRef = React.useRef<HTMLDivElement>(null);
15
16 React.useEffect(() => {
17 const container = containerRef.current;
18 if (!container) return;
19
20 const handleMouseMove = (e: MouseEvent) => {
21 const rect = container.getBoundingClientRect();
22 const x = e.clientX - rect.left;
23 const y = e.clientY - rect.top;
24 container.style.setProperty("--mouse-x", `${x}px`);
25 container.style.setProperty("--mouse-y", `${y}px`);
26 };
27
28 container.addEventListener("mousemove", handleMouseMove);
29 return () => {
30 container.removeEventListener("mousemove", handleMouseMove);
31 };
32 }, []);
33
34 const handleFocus = (e: React.FocusEvent<HTMLTextAreaElement>) => {
35 setFocused(true);
36 onFocus?.(e);
37 };
38
39 const handleBlur = (e: React.FocusEvent<HTMLTextAreaElement>) => {
40 setFocused(false);
41 onBlur?.(e);
42 };
43
44 return (
45 <div
46 ref={containerRef}
47 className={cn(
48 "group relative rounded-xl p-px transition-all duration-300",
49 "bg-neutral-800",
50 error ? "bg-red-500/50" : focused ? "bg-neutral-600" : "hover:bg-neutral-700"
51 )}
52 style={
53 {
54 "--mouse-x": "0px",
55 "--mouse-y": "0px",
56 background: error
57 ? undefined
58 : `radial-gradient(600px circle at var(--mouse-x) var(--mouse-y), rgba(255, 255, 255, 0.4), transparent 40%),
59 radial-gradient(400px circle at var(--mouse-x) var(--mouse-y), var(--textarea-border-gradient, #a78bfa), transparent 40%)`,
60 } as React.CSSProperties
61 }
62 >
63 {}
64 <div className="relative rounded-[10px] bg-neutral-950 h-full w-full overflow-hidden">
65 <textarea
66 ref={ref}
67 className={cn(
68 "w-full bg-transparent px-4 py-3 text-sm text-white placeholder:text-neutral-500 resize-none",
69 "focus:outline-none",
70 "disabled:cursor-not-allowed disabled:opacity-50",
71 "min-h-[120px]",
72 className
73 )}
74 onFocus={handleFocus}
75 onBlur={handleBlur}
76 {...props}
77 />
78 </div>
79 </div>
80 );
81 }
82);
83GlowTextArea.displayName = "GlowTextArea";
84
85export { GlowTextArea };