11"use client" ;
22
3- import { useRef , useEffect } from "react" ;
3+ import { useRef , useEffect , useState } from "react" ;
44import { cn } from "@/lib/utils" ;
55import { Input } from "./ui/input" ;
66import {
@@ -20,6 +20,11 @@ export function DataInput() {
2020 const isSeparated = config . inputs . length > 1 ;
2121 const containerRef = useRef < HTMLDivElement > ( null ) ;
2222
23+ // Add validation state tracking
24+ const [ validationState , setValidationState ] = useState <
25+ Record < string , boolean >
26+ > ( { } ) ;
27+
2328 const gridCols =
2429 {
2530 1 : "grid-cols-1" ,
@@ -28,11 +33,22 @@ export function DataInput() {
2833 4 : "grid-cols-4" ,
2934 } [ config . layout ?. columns ?? 1 ] ?? "grid-cols-1" ;
3035
31- // Handle input changes
32- const handleInputChange = ( id : string , value : string ) => {
36+ // Handle input changes with validation
37+ const handleInputChange = (
38+ id : string ,
39+ value : string ,
40+ validation ?: ( value : string ) => boolean
41+ ) => {
3342 const values = { ...data ?. data } as Record < string , string > ;
3443 values [ id ] = value ;
3544 setData ( type , values ) ;
45+
46+ if ( validation ) {
47+ setValidationState ( ( prev ) => ( {
48+ ...prev ,
49+ [ id ] : validation ( value ) ,
50+ } ) ) ;
51+ }
3652 } ;
3753
3854 // Animate height changes
@@ -54,21 +70,33 @@ export function DataInput() {
5470 < div
5571 ref = { containerRef }
5672 className = "flex flex-col gap-4 w-full relative transition-[height] duration-300 ease-in-out"
57- style = { { height : "40px" } } // Initial height of single input
73+ style = { { height : "40px" } }
5874 >
5975 < div className = "absolute w-full" >
60- < div className = { cn ( "flex relative" ) } >
76+ < div
77+ className = { cn (
78+ "flex relative rounded-md transition-all duration-200" ,
79+ ! isSeparated &&
80+ "focus-within:ring-[1.5px] focus-within:ring-primary"
81+ ) }
82+ >
6183 < DataSelect type = { type } onTypeSelect = { ( t ) => setData ( t , { } ) } />
6284 < Input
6385 type = { config . inputs [ 0 ] . type }
6486 id = { config . inputs [ 0 ] . id }
6587 value = { data ?. data ?. [ config . inputs [ 0 ] . id ] || "" }
6688 onChange = { ( e ) =>
67- handleInputChange ( config . inputs [ 0 ] . id , e . target . value )
89+ handleInputChange (
90+ config . inputs [ 0 ] . id ,
91+ e . target . value ,
92+ config . inputs [ 0 ] . validation
93+ )
6894 }
6995 className = { cn (
70- "rounded-l-none focus-visible:ring-0 focus-visible:ring-offset-0 px-3 py-0" ,
71- isSeparated && "rounded-l-md ml-3"
96+ "rounded-l-none focus-visible:ring-0 px-3 py-0" ,
97+ isSeparated && "rounded-l-md ml-3 focus-visible:ring-[1.5px]" ,
98+ validationState [ config . inputs [ 0 ] . id ] === false &&
99+ "text-destructive"
72100 ) }
73101 placeholder = { config . inputs [ 0 ] . placeholder }
74102 />
@@ -88,12 +116,15 @@ export function DataInput() {
88116 type = { input . type }
89117 id = { input . id }
90118 value = { data ?. data ?. [ input . id ] || "" }
91- onChange = { ( e ) => handleInputChange ( input . id , e . target . value ) }
119+ onChange = { ( e ) =>
120+ handleInputChange ( input . id , e . target . value , input . validation )
121+ }
92122 placeholder = { input . placeholder }
93123 className = { cn (
94124 input . className ,
95125 "animate-in fade-in duration-300 ease-in-out" ,
96- `delay-[${ index * 75 } ms]`
126+ `delay-[${ index * 75 } ms]` ,
127+ validationState [ input . id ] === false && "text-destructive"
97128 ) }
98129 />
99130 ) ) }
0 commit comments