1- import { CheckIcon } from "@heroicons/react/20/solid" ;
2- import { useCallback , useEffect , useRef , useState } from "react" ;
1+ import { useEffect , useRef , useState } from "react" ;
32import { cn } from "~/utils/cn" ;
4- import { Button } from "./Buttons" ;
5- import { ClipboardCheckIcon , ClipboardIcon } from "lucide-react" ;
3+ import { CopyButton } from "./CopyButton" ;
64
75const variants = {
86 "primary/small" : {
97 container :
108 "flex items-center text-text-dimmed font-mono rounded border bg-charcoal-750 text-xs transition hover:bg-charcoal-700 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 focus:border-transparent focus:outline-none focus:ring-0 focus:ring-transparent" ,
119 input :
1210 "bg-transparent border-0 text-xs px-2 w-auto rounded-l h-6 leading-6 focus:ring-transparent" ,
13- buttonVariant : "primary/small" as const ,
11+ buttonVariant : "primary" as const ,
12+ size : "small" as const ,
1413 button : "rounded-l-none" ,
15- iconSize : "h-3 w-3" ,
16- iconPadding : "pl-1" ,
1714 } ,
1815 "secondary/small" : {
1916 container :
2017 "flex items-center text-text-dimmed font-mono rounded border bg-charcoal-750 text-xs transition hover:bg-charcoal-700 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 focus:border-transparent focus:outline-none focus:ring-0 focus:ring-transparent" ,
2118 input :
2219 "bg-transparent border-0 text-xs px-2 w-auto rounded-l h-6 leading-6 focus:ring-transparent" ,
23- buttonVariant : "tertiary/small" as const ,
20+ buttonVariant : "tertiary" as const ,
21+ size : "small" as const ,
2422 button : "rounded-l-none border-l border-charcoal-750" ,
25- iconSize : "h-3 w-3" ,
26- iconPadding : "pl-1" ,
2723 } ,
2824 "tertiary/small" : {
2925 container :
3026 "group/clipboard flex items-center text-text-dimmed font-mono rounded bg-transparent border border-transparent text-xs transition duration-150 hover:border-charcoal-700 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 focus:border-transparent focus:outline-none focus:ring-0 focus:ring-transparent" ,
3127 input :
3228 "bg-transparent border-0 text-xs px-2 w-auto rounded-l h-6 leading-6 focus:ring-transparent" ,
33- buttonVariant : "minimal/small" as const ,
29+ buttonVariant : "minimal" as const ,
30+ size : "small" as const ,
3431 button :
3532 "rounded-l-none border-l border-transparent transition group-hover/clipboard:border-charcoal-700" ,
36- iconSize : "h-3 w-3" ,
37- iconPadding : "pl-1" ,
3833 } ,
3934 "primary/medium" : {
4035 container :
4136 "flex items-center text-text-dimmed font-mono rounded border bg-charcoal-750 text-sm transition hover:bg-charcoal-700 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 focus:border-transparent focus:outline-none focus:ring-0 focus:ring-transparent" ,
4237 input :
4338 "bg-transparent border-0 text-sm px-3 w-auto rounded-l h-8 leading-6 focus:ring-transparent" ,
44- buttonVariant : "primary/medium" as const ,
39+ buttonVariant : "primary" as const ,
40+ size : "medium" as const ,
4541 button : "rounded-l-none" ,
46- iconSize : "h-4 w-4" ,
47- iconPadding : "pl-2" ,
4842 } ,
4943 "secondary/medium" : {
5044 container :
5145 "flex items-center text-text-dimmed font-mono rounded bg-charcoal-750 text-sm transition hover:bg-charcoal-700 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 focus:border-transparent focus:outline-none focus:ring-0 focus:ring-transparent" ,
5246 input :
5347 "bg-transparent border-0 text-sm px-3 w-auto rounded-l h-8 leading-6 focus:ring-transparent" ,
54- buttonVariant : "tertiary/medium" as const ,
48+ buttonVariant : "tertiary" as const ,
49+ size : "medium" as const ,
5550 button : "rounded-l-none border-l border-charcoal-750" ,
56- iconSize : "h-4 w-4" ,
57- iconPadding : "pl-2" ,
5851 } ,
5952 "tertiary/medium" : {
6053 container :
6154 "group flex items-center text-text-dimmed font-mono rounded bg-transparent border border-transparent text-sm transition hover:border-charcoal-700 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 focus:border-transparent focus:outline-none focus:ring-0 focus:ring-transparent" ,
6255 input :
6356 "bg-transparent border-0 text-sm px-3 w-auto rounded-l h-8 leading-6 focus:ring-transparent" ,
64- buttonVariant : "minimal/medium" as const ,
57+ buttonVariant : "minimal" as const ,
58+ size : "medium" as const ,
6559 button : "rounded-l-none border-l border-transparent transition group-hover:border-charcoal-700" ,
66- iconSize : "h-4 w-4" ,
67- iconPadding : "pl-2" ,
6860 } ,
6961} ;
7062
@@ -88,36 +80,19 @@ export function ClipboardField({
8880 fullWidth = true ,
8981} : ClipboardFieldProps ) {
9082 const [ isSecure , setIsSecure ] = useState ( secure !== undefined && secure ) ;
91- const [ copied , setCopied ] = useState ( false ) ;
92-
93- const copy = useCallback (
94- ( event : React . MouseEvent < HTMLButtonElement > ) => {
95- event . preventDefault ( ) ;
96- event . stopPropagation ( ) ;
97- navigator . clipboard . writeText ( value ) ;
98- setCopied ( true ) ;
99- setTimeout ( ( ) => {
100- setCopied ( false ) ;
101- } , 1500 ) ;
102- } ,
103- [ value ]
104- ) ;
83+ const inputIcon = useRef < HTMLInputElement > ( null ) ;
84+ const { container, input, buttonVariant, button, size } = variants [ variant ] ;
10585
10686 useEffect ( ( ) => {
10787 setIsSecure ( secure !== undefined && secure ) ;
10888 } , [ secure ] ) ;
10989
110- const { container, input, buttonVariant, button } = variants [ variant ] ;
111- const iconClassName = variants [ variant ] . iconSize ;
112- const iconPosition = variants [ variant ] . iconPadding ;
113- const inputIcon = useRef < HTMLInputElement > ( null ) ;
114-
11590 return (
11691 < span className = { cn ( container , fullWidth ? "w-full" : "max-w-fit" , className ) } >
11792 { icon && (
11893 < span
11994 onClick = { ( ) => inputIcon . current && inputIcon . current . focus ( ) }
120- className = { cn ( iconPosition , "flex items-center" ) }
95+ className = "flex items-center pl-1"
12196 >
12297 { icon }
12398 </ span >
@@ -132,51 +107,26 @@ export function ClipboardField({
132107 fullWidth ? "w-full" : "max-w-fit" ,
133108 input
134109 ) }
135- // size={value.length}
136- // maxLength={3}
137110 onFocus = { ( e ) => {
138111 if ( secure ) {
139- setIsSecure ( ( i ) => false ) ;
112+ setIsSecure ( false ) ;
140113 }
141114 e . currentTarget . select ( ) ;
142115 } }
143116 onBlur = { ( ) => {
144117 if ( secure ) {
145- setIsSecure ( ( i ) => true ) ;
118+ setIsSecure ( true ) ;
146119 }
147120 } }
148121 />
149- { iconButton ? (
150- < Button
151- variant = { buttonVariant }
152- onClick = { copy }
153- className = { cn ( "shrink grow-0 px-1.5" , button ) }
154- >
155- { copied ? (
156- < ClipboardCheckIcon
157- className = { cn (
158- "h-4 w-4" ,
159- buttonVariant === "primary/small" || buttonVariant === "primary/medium"
160- ? "text-background-dimmed"
161- : "text-green-500"
162- ) }
163- />
164- ) : (
165- < ClipboardIcon
166- className = { cn (
167- "h-4 w-4" ,
168- buttonVariant === "primary/small" || buttonVariant === "primary/medium"
169- ? "text-background-dimmed"
170- : "text-text-dimmed"
171- ) }
172- />
173- ) }
174- </ Button >
175- ) : (
176- < Button variant = { buttonVariant } onClick = { copy } className = { cn ( "shrink-0 grow-0" , button ) } >
177- { copied ? < CheckIcon className = "mx-[0.4rem] h-4 w-4 text-green-500" /> : "Copy" }
178- </ Button >
179- ) }
122+ < CopyButton
123+ value = { value }
124+ variant = { iconButton ? "icon" : "button" }
125+ buttonVariant = { buttonVariant }
126+ size = { size }
127+ buttonClassName = { button }
128+ showTooltip = { false }
129+ />
180130 </ span >
181131 ) ;
182132}
0 commit comments