@@ -15,6 +15,8 @@ import { composeClasses } from 'lib/classes'
1515import { Flex } from 'components/Layout'
1616import Tooltip from 'components/Tooltip'
1717import { Button } from 'components/Buttons'
18+ import Skeleton from 'components/Skeleton'
19+ import Spinner from 'components/Spinner'
1820import ProgressBar from '../../ProgressBar/ProgressBar'
1921import Text from '../../Typography/Text'
2022
@@ -31,6 +33,11 @@ export interface InputFileProps extends React.HTMLProps<HTMLInputElement> {
3133 onView ?: ( e : React . MouseEvent < HTMLButtonElement > ) => void
3234 onDownload ?: ( e : React . MouseEvent < HTMLButtonElement > ) => void
3335 onDelete ?: ( e : React . MouseEvent < HTMLButtonElement > ) => void
36+ fileName ?: string
37+ isLoading ?: boolean
38+ isLoadingDelete ?: boolean
39+ isLoadingDownload ?: boolean
40+ isLoadingView ?: boolean
3441}
3542
3643export function InputFile ( {
@@ -93,22 +100,51 @@ export function InputFile({
93100 * is a function that works to delete the file
94101 */
95102 onDelete,
103+ /**
104+ * is a file that works to set the value of the file
105+ */
106+ fileName,
107+ /**
108+ * is a boolean that works to indicate if the file is loading
109+ */
110+ isLoading,
111+ /**
112+ * is a boolean that works to indicate if the file is loading
113+ */
114+ isLoadingDelete,
115+ /**
116+ * is a boolean that works to indicate if the file is loading
117+ */
118+ isLoadingDownload,
119+ /**
120+ * is a boolean that works to indicate if the file is loading
121+ */
122+ isLoadingView,
96123 ...otherProps
97124} : InputFileProps ) {
98125 const [ isDrag , setIsDrag ] = useState < boolean > ( false )
99- const [ file , setFile ] = useState < FileList | null > ( null )
126+ const [ fileList , setFileList ] = useState < FileList | null > ( null )
127+
100128 const disabled = otherProps . disabled || false
101129
102130 const handleChange = useCallback (
103131 ( event : ChangeEvent < HTMLInputElement > ) => {
104132 if ( disabled ) return
105133 setIsDrag ( false )
106- setFile ( event . target . files )
134+ setFileList ( event . target . files )
107135 onChange && onChange ( event )
108136 } ,
109137 [ isDrag , onChange ]
110138 )
111139
140+ const handleDelete = useCallback (
141+ ( e : React . MouseEvent < HTMLButtonElement > ) => {
142+ setFileList ( null )
143+ onDelete && onDelete ( e )
144+ } ,
145+ [ onDelete ]
146+ )
147+
112148 return (
113149 < label
114150 role = { roleContainer }
@@ -129,7 +165,7 @@ export function InputFile({
129165 </ Tooltip >
130166 ) }
131167 </ Flex >
132- { ! ( singleFile && file ?. length ) && (
168+ { ! ( singleFile && fileList ?. length ) && ! ! ( singleFile && ! fileName ) && (
133169 < Flex alignItems = "center" gap = "2" >
134170 < UploadIcon className = "w-4 h-4 text-blue-700" />
135171 < Text variant = "small" className = "text-blue-700" >
@@ -158,6 +194,7 @@ export function InputFile({
158194 if ( disabled ) return
159195 setIsDrag ( true )
160196 } }
197+ multiple = { ! singleFile }
161198 disabled = { progressIndicator >= 1 || disabled }
162199 className = { composeClasses (
163200 'opacity-0 absolute top-0 left-0 bottom-0 right-0' ,
@@ -179,7 +216,7 @@ export function InputFile({
179216 < UploadIcon className = "w-4 h-4 text-gray-400 flex-shrink-0" />
180217 < Flex className = "w-full flex-col" gap = "1" >
181218 < Text textMuted500 style = { { fontSize : '10px' } } >
182- { file ?. item ( 0 ) ?. name }
219+ { fileList ?. item ( 0 ) ?. name }
183220 </ Text >
184221 < ProgressBar
185222 value = { progressIndicator }
@@ -190,57 +227,74 @@ export function InputFile({
190227 </ Flex >
191228 </ Flex >
192229 ) }
193- { singleFile && file ?. length === 1 && ! error ?. show && (
194- < Flex
195- justifyContent = "between"
196- alignItems = "center"
197- gap = "2"
198- className = "w-full z-10"
199- onClick = { ( e ) => {
200- e . preventDefault ( )
201- e . stopPropagation ( )
202- } }
203- >
204- < Flex alignItems = "center" gap = "2" >
205- < PaperClipIcon className = "w-4 h-4 text-gray-400 flex-shrink-0" />
206- < Text size = "xs" className = "whitespace-nowrap" >
207- { file . item ( 0 ) ?. name }
208- </ Text >
230+ { isLoading && < Skeleton className = "w-full h-5 rounded-full" /> }
231+ { singleFile &&
232+ ( fileList ?. length === 1 || fileName ) &&
233+ ! error ?. show &&
234+ ! isLoading &&
235+ ! progressIndicator && (
236+ < Flex
237+ justifyContent = "between"
238+ alignItems = "center"
239+ gap = "2"
240+ className = "w-full z-10"
241+ onClick = { ( e ) => {
242+ e . preventDefault ( )
243+ e . stopPropagation ( )
244+ } }
245+ >
246+ < Flex alignItems = "center" gap = "2" >
247+ < PaperClipIcon className = "w-4 h-4 text-gray-400 flex-shrink-0" />
248+ < Text size = "xs" className = "whitespace-nowrap" >
249+ { fileList ?. item ( 0 ) ?. name || fileName }
250+ </ Text >
251+ </ Flex >
252+ < Flex alignItems = "center" gap = "2" >
253+ { onView && (
254+ < Button
255+ variant = "ghost"
256+ padding = "0.5"
257+ className = "rounded-full"
258+ onClick = { onView }
259+ >
260+ { isLoadingView ? (
261+ < Spinner width = "18px" height = "18px" color = "#1D4ED8" />
262+ ) : (
263+ < EyeIcon className = "w-4 h-4 text-gray-400 flex-shrink-0 cursor-pointer" />
264+ ) }
265+ </ Button >
266+ ) }
267+ { onDownload && (
268+ < Button
269+ variant = "ghost"
270+ padding = "0.5"
271+ className = "rounded-full"
272+ onClick = { onDownload }
273+ >
274+ { isLoadingDownload ? (
275+ < Spinner width = "18px" height = "18px" color = "#1D4ED8" />
276+ ) : (
277+ < DownloadIcon className = "w-4 h-4 text-gray-400 flex-shrink-0" />
278+ ) }
279+ </ Button >
280+ ) }
281+ { onDelete && (
282+ < Button
283+ variant = "ghost"
284+ padding = "0.5"
285+ className = "rounded-full"
286+ onClick = { handleDelete }
287+ >
288+ { isLoadingDelete ? (
289+ < Spinner width = "18px" height = "18px" color = "#DC2626" />
290+ ) : (
291+ < TrashIcon className = "w-4 h-4 text-red-500 flex-shrink-0" />
292+ ) }
293+ </ Button >
294+ ) }
295+ </ Flex >
209296 </ Flex >
210- < Flex alignItems = "center" gap = "2" >
211- { onView && (
212- < Button
213- variant = "ghost"
214- padding = "0.5"
215- className = "rounded-full"
216- onClick = { onView }
217- >
218- < EyeIcon className = "w-4 h-4 text-gray-400 flex-shrink-0 cursor-pointer" />
219- </ Button >
220- ) }
221- { onDownload && (
222- < Button
223- variant = "ghost"
224- padding = "0.5"
225- className = "rounded-full"
226- onClick = { onDownload }
227- >
228- < DownloadIcon className = "w-4 h-4 text-gray-400 flex-shrink-0" />
229- </ Button >
230- ) }
231- { onDelete && (
232- < Button
233- variant = "ghost"
234- padding = "0.5"
235- className = "rounded-full"
236- onClick = { onDelete }
237- >
238- < TrashIcon className = "w-4 h-4 text-red-500 flex-shrink-0" />
239- </ Button >
240- ) }
241- </ Flex >
242- </ Flex >
243- ) }
297+ ) }
244298 </ div >
245299 </ label >
246300 )
0 commit comments