Skip to content

Commit 42d56ce

Browse files
committed
fix(ffe-file-upload-react): håndter iOS bildenavn og forbedre tilgjengelighet
- Legg til unik navngenerering for iOS kamerabilder som alltid får navnet 'image.jpg' - Fiks ESLint feil med no-shadow ved å endre parameternavn - Forbedre tilgjengelighet med tastatur og skjermleser støtte - Legg til korrekt ARIA-roller og tastaturfunksjonalitet
1 parent 7b65209 commit 42d56ce

File tree

1 file changed

+48
-35
lines changed

1 file changed

+48
-35
lines changed

packages/ffe-file-upload-react/src/FileUpload.tsx

+48-35
Original file line numberDiff line numberDiff line change
@@ -4,53 +4,41 @@ import classNames from 'classnames';
44
import { SecondaryButton } from '@sb1/ffe-buttons-react';
55
import { Icon } from '@sb1/ffe-icons-react';
66

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+
726
export interface FileUploadProps<Document> {
8-
/** ID for the input field. The ID is used as a base for the label ID as well. */
927
id: string;
10-
/** Label for the button to trigger native upload handling. */
1128
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-
* */
1729
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-
*/
2430
onFilesSelected(fileList: FileList | null): void;
25-
/** Will be called when objects are dropped over the upload-section. */
2631
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-
*/
3132
onFileDeleted(file: FileItemProps<Document>['file']): void;
32-
/** Whether or not uploading multiple files at once via the native file handler is allowed*/
3333
multiple?: boolean;
34-
/** Title module */
3534
title: string;
36-
/** Text on the info-section */
3735
infoText: string;
38-
/** Subtext on the info-section */
3936
infoSubText?: string;
40-
/** Label for the cancel button */
4137
cancelText?: string;
42-
/** Label for the delete button */
4338
deleteText?: string;
44-
/** Title on the upload-section */
4539
uploadTitle: string;
46-
/** MicroText on the upload-section */
4740
uploadMicroText: string;
48-
/** SubText on the upload-section */
4941
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-
*/
5442
accept?: string;
5543
}
5644

@@ -77,26 +65,48 @@ export function FileUpload<Document>({
7765
const downloadIcon =
7866
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgLTk2MCA5NjAgOTYwIiB3aWR0aD0iMjQiPjxwYXRoIGQ9Ik00ODAtMzQzLjUzOXEtNy4yMzEgMC0xMy40NjEtMi4zMDgtNi4yMzEtMi4zMDctMTEuODQ2LTcuOTIzTDMzMC4zMDktNDc4LjE1M3EtOC45MjMtOC45MjMtOC44MDctMjAuODg0LjExNS0xMS45NjEgOC44MDctMjEuMjY5IDkuMzA4LTkuMzA3IDIxLjM4NC05LjYxNSAxMi4wNzctLjMwOCAyMS4zODUgOWw3Ni45MjMgNzYuOTIzdi0zMDYuMDAxcTAtMTIuNzY5IDguNjE1LTIxLjM4NCA4LjYxNS04LjYxNiAyMS4zODQtOC42MTZ0MjEuMzg0IDguNjE2cTguNjE1IDguNjE1IDguNjE1IDIxLjM4NHYzMDYuMDAxbDc2LjkyMy03Ni45MjNxOC45MjMtOC45MjMgMjEuMTkyLTguODA4IDEyLjI2OS4xMTYgMjEuNTc3IDkuNDIzIDguNjkyIDkuMzA4IDguOTk5IDIxLjA3Ny4zMDggMTEuNzY5LTguOTk5IDIxLjA3Nkw1MDUuMzA3LTM1My43N3EtNS42MTUgNS42MTYtMTEuODQ2IDcuOTIzLTYuMjMgMi4zMDgtMTMuNDYxIDIuMzA4Wk0yNTIuMzA5LTE4MC4wMDFxLTMwLjMwOCAwLTUxLjMwOC0yMXQtMjEtNTEuMzA4di03OC40NjFxMC0xMi43NjkgOC42MTYtMjEuMzg0IDguNjE1LTguNjE1IDIxLjM4NC04LjYxNXQyMS4zODQgOC42MTVRMjQwLTM0My41MzkgMjQwLTMzMC43N3Y3OC40NjFxMCA0LjYxNiAzLjg0NiA4LjQ2MyAzLjg0NyAzLjg0NiA4LjQ2MyAzLjg0Nmg0NTUuMzgycTQuNjE2IDAgOC40NjMtMy44NDYgMy44NDYtMy44NDcgMy44NDYtOC40NjN2LTc4LjQ2MXEwLTEyLjc2OSA4LjYxNS0yMS4zODR0MjEuMzg0LTguNjE1cTEyLjc2OSAwIDIxLjM4NCA4LjYxNSA4LjYxNiA4LjYxNSA4LjYxNiAyMS4zODR2NzguNDYxcTAgMzAuMzA4LTIxIDUxLjMwOHQtNTEuMzA4IDIxSDI1Mi4zMDlaIi8+PC9zdmc+';
7967

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+
8082
const handleFilesDropped = (event: React.DragEvent<HTMLDivElement>) => {
8183
event.preventDefault();
8284
setIsHover(false);
83-
onFilesDropped(event.dataTransfer.files);
85+
const processedFiles = processFiles(event.dataTransfer.files);
86+
onFilesDropped(processedFiles);
8487
};
8588

8689
const handleFileDeleted = (event: React.MouseEvent<HTMLButtonElement>) => {
8790
onFileDeleted(files[event.currentTarget.id]);
8891
};
8992

9093
const triggerUploadFileNativeHandler = () => {
91-
// clear file input to trigger onChange when uploading same filename
9294
if (fileInputElement.current) {
9395
fileInputElement.current.value = '';
9496
fileInputElement.current.click();
9597
}
9698
};
9799

98100
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+
}
100110
};
101111

102112
return (
@@ -124,7 +134,6 @@ export function FileUpload<Document>({
124134
</div>
125135
</div>
126136
)}
127-
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
128137
<div
129138
className="ffe-file-upload__upload-section"
130139
onDrop={handleFilesDropped}
@@ -133,6 +142,10 @@ export function FileUpload<Document>({
133142
setIsHover(true);
134143
}}
135144
onDragLeave={() => setIsHover(false)}
145+
role="button"
146+
tabIndex={0}
147+
onKeyDown={handleKeyDown}
148+
aria-label={label}
136149
>
137150
<div
138151
className={classNames(

0 commit comments

Comments
 (0)