@@ -4,53 +4,41 @@ import classNames from 'classnames';
4
4
import { SecondaryButton } from '@sb1/ffe-buttons-react' ;
5
5
import { Icon } from '@sb1/ffe-icons-react' ;
6
6
7
+ // Helper function to generate a unique filename
8
+ const generateUniqueFileName = ( originalFile : File ) : File => {
9
+ // If it's not an iOS "image.jpg" case, return the original file
10
+ if ( originalFile . name !== 'image.jpg' ) {
11
+ return originalFile ;
12
+ }
13
+
14
+ // Create a unique name for iOS images
15
+ const timestamp = new Date ( ) . getTime ( ) ;
16
+ const randomString = Math . random ( ) . toString ( 36 ) . substring ( 2 , 8 ) ;
17
+ const newName = `image_${ timestamp } _${ randomString } .jpg` ;
18
+
19
+ // Create a new File object with the unique name
20
+ return new File ( [ originalFile ] , newName , {
21
+ type : originalFile . type ,
22
+ lastModified : originalFile . lastModified ,
23
+ } ) ;
24
+ } ;
25
+
7
26
export interface FileUploadProps < Document > {
8
- /** ID for the input field. The ID is used as a base for the label ID as well. */
9
27
id : string ;
10
- /** Label for the button to trigger native upload handling. */
11
28
label : string ;
12
- /**
13
- * A map of files, indexed by file name (check file-shape on FileItem.js propTypes), that the user has uploaded.
14
- * Must be maintained outside of `FileUpload`. It is up to the implementation to deny or accept file types, sizes, etc,
15
- * and it is important that duplicates are not allowed.
16
- * */
17
29
files : Record < string , FileItemProps < Document > [ 'file' ] > ;
18
- /**
19
- * Will be called with `FileList`-object containing the `File`-objects the user selected.
20
- * See MDN for documentation on
21
- * [FileList](https://developer.mozilla.org/en-US/docs/Web/API/FileList) and
22
- * [File](https://developer.mozilla.org/en-US/docs/Web/API/File).
23
- */
24
30
onFilesSelected ( fileList : FileList | null ) : void ;
25
- /** Will be called when objects are dropped over the upload-section. */
26
31
onFilesDropped ( fileList : FileList | null ) : void ;
27
- /**
28
- * Called when the user clicks the delete button for a given file. Is called with the `File`
29
- * object of the file in question.
30
- */
31
32
onFileDeleted ( file : FileItemProps < Document > [ 'file' ] ) : void ;
32
- /** Whether or not uploading multiple files at once via the native file handler is allowed*/
33
33
multiple ?: boolean ;
34
- /** Title module */
35
34
title : string ;
36
- /** Text on the info-section */
37
35
infoText : string ;
38
- /** Subtext on the info-section */
39
36
infoSubText ?: string ;
40
- /** Label for the cancel button */
41
37
cancelText ?: string ;
42
- /** Label for the delete button */
43
38
deleteText ?: string ;
44
- /** Title on the upload-section */
45
39
uploadTitle : string ;
46
- /** MicroText on the upload-section */
47
40
uploadMicroText : string ;
48
- /** SubText on the upload-section */
49
41
uploadSubText : string ;
50
- /** Unique file type specifier that describes a type of file that may be selected by the user, e.g. ".pdf"
51
- * See MDN for documentation on
52
- * [Unique file type specifiers](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers)
53
- */
54
42
accept ?: string ;
55
43
}
56
44
@@ -77,26 +65,48 @@ export function FileUpload<Document>({
77
65
const downloadIcon =
78
66
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgLTk2MCA5NjAgOTYwIiB3aWR0aD0iMjQiPjxwYXRoIGQ9Ik00ODAtMzQzLjUzOXEtNy4yMzEgMC0xMy40NjEtMi4zMDgtNi4yMzEtMi4zMDctMTEuODQ2LTcuOTIzTDMzMC4zMDktNDc4LjE1M3EtOC45MjMtOC45MjMtOC44MDctMjAuODg0LjExNS0xMS45NjEgOC44MDctMjEuMjY5IDkuMzA4LTkuMzA3IDIxLjM4NC05LjYxNSAxMi4wNzctLjMwOCAyMS4zODUgOWw3Ni45MjMgNzYuOTIzdi0zMDYuMDAxcTAtMTIuNzY5IDguNjE1LTIxLjM4NCA4LjYxNS04LjYxNiAyMS4zODQtOC42MTZ0MjEuMzg0IDguNjE2cTguNjE1IDguNjE1IDguNjE1IDIxLjM4NHYzMDYuMDAxbDc2LjkyMy03Ni45MjNxOC45MjMtOC45MjMgMjEuMTkyLTguODA4IDEyLjI2OS4xMTYgMjEuNTc3IDkuNDIzIDguNjkyIDkuMzA4IDguOTk5IDIxLjA3Ny4zMDggMTEuNzY5LTguOTk5IDIxLjA3Nkw1MDUuMzA3LTM1My43N3EtNS42MTUgNS42MTYtMTEuODQ2IDcuOTIzLTYuMjMgMi4zMDgtMTMuNDYxIDIuMzA4Wk0yNTIuMzA5LTE4MC4wMDFxLTMwLjMwOCAwLTUxLjMwOC0yMXQtMjEtNTEuMzA4di03OC40NjFxMC0xMi43NjkgOC42MTYtMjEuMzg0IDguNjE1LTguNjE1IDIxLjM4NC04LjYxNXQyMS4zODQgOC42MTVRMjQwLTM0My41MzkgMjQwLTMzMC43N3Y3OC40NjFxMCA0LjYxNiAzLjg0NiA4LjQ2MyAzLjg0NyAzLjg0NiA4LjQ2MyAzLjg0Nmg0NTUuMzgycTQuNjE2IDAgOC40NjMtMy44NDYgMy44NDYtMy44NDcgMy44NDYtOC40NjN2LTc4LjQ2MXEwLTEyLjc2OSA4LjYxNS0yMS4zODR0MjEuMzg0LTguNjE1cTEyLjc2OSAwIDIxLjM4NCA4LjYxNSA4LjYxNiA4LjYxNSA4LjYxNiAyMS4zODR2NzguNDYxcTAgMzAuMzA4LTIxIDUxLjMwOHQtNTEuMzA4IDIxSDI1Mi4zMDlaIi8+PC9zdmc+' ;
79
67
68
+ const processFiles = ( inputFiles : FileList | null ) : FileList | null => {
69
+ if ( ! inputFiles ) return null ;
70
+
71
+ // Create a new array of processed files
72
+ const processedFiles = Array . from ( inputFiles ) . map (
73
+ generateUniqueFileName ,
74
+ ) ;
75
+
76
+ // Convert back to FileList-like object
77
+ const dataTransfer = new DataTransfer ( ) ;
78
+ processedFiles . forEach ( file => dataTransfer . items . add ( file ) ) ;
79
+ return dataTransfer . files ;
80
+ } ;
81
+
80
82
const handleFilesDropped = ( event : React . DragEvent < HTMLDivElement > ) => {
81
83
event . preventDefault ( ) ;
82
84
setIsHover ( false ) ;
83
- onFilesDropped ( event . dataTransfer . files ) ;
85
+ const processedFiles = processFiles ( event . dataTransfer . files ) ;
86
+ onFilesDropped ( processedFiles ) ;
84
87
} ;
85
88
86
89
const handleFileDeleted = ( event : React . MouseEvent < HTMLButtonElement > ) => {
87
90
onFileDeleted ( files [ event . currentTarget . id ] ) ;
88
91
} ;
89
92
90
93
const triggerUploadFileNativeHandler = ( ) => {
91
- // clear file input to trigger onChange when uploading same filename
92
94
if ( fileInputElement . current ) {
93
95
fileInputElement . current . value = '' ;
94
96
fileInputElement . current . click ( ) ;
95
97
}
96
98
} ;
97
99
98
100
const handleFileSelected = ( event : React . ChangeEvent < HTMLInputElement > ) => {
99
- onFilesSelected ( event . target . files ) ;
101
+ const processedFiles = processFiles ( event . target . files ) ;
102
+ onFilesSelected ( processedFiles ) ;
103
+ } ;
104
+
105
+ const handleKeyDown = ( event : React . KeyboardEvent < HTMLDivElement > ) => {
106
+ if ( event . key === 'Enter' || event . key === ' ' ) {
107
+ event . preventDefault ( ) ;
108
+ triggerUploadFileNativeHandler ( ) ;
109
+ }
100
110
} ;
101
111
102
112
return (
@@ -124,7 +134,6 @@ export function FileUpload<Document>({
124
134
</ div >
125
135
</ div >
126
136
) }
127
- { /* eslint-disable-next-line jsx-a11y/no-static-element-interactions */ }
128
137
< div
129
138
className = "ffe-file-upload__upload-section"
130
139
onDrop = { handleFilesDropped }
@@ -133,6 +142,10 @@ export function FileUpload<Document>({
133
142
setIsHover ( true ) ;
134
143
} }
135
144
onDragLeave = { ( ) => setIsHover ( false ) }
145
+ role = "button"
146
+ tabIndex = { 0 }
147
+ onKeyDown = { handleKeyDown }
148
+ aria-label = { label }
136
149
>
137
150
< div
138
151
className = { classNames (
0 commit comments