11import * as React from 'react'
22
33import { cn } from '../../lib/utils'
4+ import { useEffect , useRef , useState } from 'react'
45
5- function Input ( { className, type, ...props } : React . ComponentProps < 'input' > ) {
6- return (
6+ interface OwnProps {
7+ // Something that needs to appear before the start, outside the field
8+ beforeStartDecoration ?: React . ReactNode
9+
10+ // Something that needs to appear at the start, inside the field
11+ startDecoration ?: React . ReactNode
12+
13+ // Something that needs to appear at the end, inside the field
14+ endDecoration ?: React . ReactNode
15+
16+ // Something that needs to appear after the end, outside the field
17+ afterEndDecoration ?: React . ReactNode
18+ }
19+
20+ function Input ( {
21+ className,
22+ type,
23+ beforeStartDecoration,
24+ startDecoration,
25+ endDecoration,
26+ afterEndDecoration,
27+ ...props
28+ } : React . ComponentProps < 'input' > & OwnProps ) {
29+ const startDecorationRef = useRef < HTMLSpanElement > ( null )
30+ const [ startDecorationWidth , setStartDecorationWidth ] = useState < number > ( 0 )
31+ const endDecorationRef = useRef < HTMLSpanElement > ( null )
32+ const [ endDecorationWidth , setEndDecorationWidth ] = useState < number > ( 0 )
33+
34+ useEffect ( ( ) => {
35+ if ( ! ! startDecoration && ! ! startDecorationRef . current ) {
36+ const rect = startDecorationRef . current . getBoundingClientRect ( )
37+ setStartDecorationWidth ( rect . width )
38+ } else {
39+ setStartDecorationWidth ( 0 )
40+ }
41+ } , [ startDecoration , startDecorationRef . current ] )
42+
43+ useEffect ( ( ) => {
44+ if ( ! ! endDecoration && ! ! endDecorationRef . current ) {
45+ const rect = endDecorationRef . current . getBoundingClientRect ( )
46+ setEndDecorationWidth ( rect . width )
47+ } else {
48+ setEndDecorationWidth ( 0 )
49+ }
50+ } , [ endDecoration , endDecorationRef . current ] ) // Re-run if content changes
51+
52+ const startStyle = ! ! startDecorationWidth ? { paddingLeft : `${ 16 + startDecorationWidth } px` } : { }
53+ const endStyle = ! ! endDecorationWidth ? { paddingRight : `${ 16 + endDecorationWidth } px` } : { }
54+
55+ const input = (
756 < input
857 type = { type }
958 data-slot = "input"
@@ -13,9 +62,32 @@ function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
1362 'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive' ,
1463 className
1564 ) }
65+ style = { { ...startStyle , ...endStyle } }
1666 { ...props }
1767 />
1868 )
69+
70+ // const hasInsideDecorations = !!startDecoration || !!endDecoration
71+ // const hasOutsideDecorations = !!beforeStartDecoration || !!afterEndDecoration
72+ return (
73+ < >
74+ { beforeStartDecoration }
75+ < div className = { 'relative' } >
76+ { ! ! startDecoration && (
77+ < span className = { 'absolute left-2.5 top-2.5' } ref = { startDecorationRef } >
78+ { startDecoration }
79+ </ span >
80+ ) }
81+ { input }
82+ { ! ! endDecoration && (
83+ < span className = { 'absolute right-2.5 top-2.5' } ref = { endDecorationRef } >
84+ { endDecoration }
85+ </ span >
86+ ) }
87+ </ div >
88+ { afterEndDecoration }
89+ </ >
90+ )
1991}
2092
2193export { Input }
0 commit comments