Skip to content

Commit 26e39a7

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 26e39a7

File tree

1 file changed

+78
-9
lines changed

1 file changed

+78
-9
lines changed

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

+78-9
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,66 @@ export interface FileUploadProps<Document> {
5454
accept?: string;
5555
}
5656

57+
/**
58+
* En komponent for opplasting av filer, som kan brukes til å håndtere dokumentopplasting i ulike formater.
59+
*
60+
* Filer kan lastes opp på to måter:
61+
* 1. Via den native filopplastingsdialogen i nettleseren
62+
* 2. Ved å dra og slippe filer direkte i opplastingssonen
63+
*
64+
* Filhåndteringsflyt:
65+
* 1. Brukeren velger filer via opplastingsdialog eller drag-and-drop
66+
* 2. Nettleseren sender event-callback med info om valgte filer
67+
* 3. Konsumenten må selv hente filinnholdet fra brukerens filsystem
68+
* 4. Konsumenten oppretter et objekt med filinformasjon som sendes til komponenten
69+
* 5. Validering av filstørrelse og type må håndteres av konsumenten
70+
*
71+
* Files-objektet er indeksert på filnavn og har følgende struktur:
72+
* @example
73+
* ```typescript
74+
* const files = {
75+
* fileBeingUploaded: {
76+
* name: 'fileBeingUploaded',
77+
* },
78+
* fileWithError: {
79+
* name: 'fileWithError',
80+
* error: 'Feil filtype',
81+
* },
82+
* fileUploaded: {
83+
* name: 'fileUploaded',
84+
* document: {
85+
* content: '(data)',
86+
* },
87+
* },
88+
* };
89+
* ```
90+
*
91+
* Merk:
92+
* - Komponenten er tilstandsløs - all filhåndtering må gjøres i foreldrekomponenten
93+
* - Duplikate filnavn støttes ikke
94+
* - Ved opplasting fra iOS-kamera må filnavnhåndtering implementeres i konsumenten
95+
*
96+
* @template Document - Type for dokumentobjektet som kan legges til i files-objektet
97+
* @param {Object} props - Komponentens props
98+
* @param {string} props.id - ID for input-feltet
99+
* @param {string} props.label - Tekst på knappen for filopplasting
100+
* @param {Record<string, FileItemProps<Document>['file']>} props.files - Objekt med filer indeksert på filnavn
101+
* @param {string} [props.cancelText] - Tekst på avbryt-knappen
102+
* @param {string} [props.deleteText] - Tekst på slett-knappen
103+
* @param {boolean} [props.multiple] - Om flere filer kan lastes opp samtidig
104+
* @param {string} props.title - Tittel på modulen
105+
* @param {string} props.infoText - Tekst i info-seksjonen
106+
* @param {string} [props.infoSubText] - Undertekst i info-seksjonen
107+
* @param {string} props.uploadTitle - Tittel på opplastingsseksjonen
108+
* @param {string} props.uploadMicroText - Mikrotekst i opplastingsseksjonen
109+
* @param {string} props.uploadSubText - Undertekst i opplastingsseksjonen
110+
* @param {string} [props.accept] - Filtypespesifikasjon (f.eks. ".pdf")
111+
* @param {(fileList: FileList | null) => void} props.onFilesDropped - Callback når filer droppes
112+
* @param {(file: FileItemProps<Document>['file']) => void} props.onFileDeleted - Callback når en fil slettes
113+
* @param {(fileList: FileList | null) => void} props.onFilesSelected - Callback når filer velges
114+
*
115+
* @returns {JSX.Element} FileUpload-komponenten
116+
*/
57117
export function FileUpload<Document>({
58118
id,
59119
label,
@@ -77,6 +137,20 @@ export function FileUpload<Document>({
77137
const downloadIcon =
78138
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgLTk2MCA5NjAgOTYwIiB3aWR0aD0iMjQiPjxwYXRoIGQ9Ik00ODAtMzQzLjUzOXEtNy4yMzEgMC0xMy40NjEtMi4zMDgtNi4yMzEtMi4zMDctMTEuODQ2LTcuOTIzTDMzMC4zMDktNDc4LjE1M3EtOC45MjMtOC45MjMtOC44MDctMjAuODg0LjExNS0xMS45NjEgOC44MDctMjEuMjY5IDkuMzA4LTkuMzA3IDIxLjM4NC05LjYxNSAxMi4wNzctLjMwOCAyMS4zODUgOWw3Ni45MjMgNzYuOTIzdi0zMDYuMDAxcTAtMTIuNzY5IDguNjE1LTIxLjM4NCA4LjYxNS04LjYxNiAyMS4zODQtOC42MTZ0MjEuMzg0IDguNjE2cTguNjE1IDguNjE1IDguNjE1IDIxLjM4NHYzMDYuMDAxbDc2LjkyMy03Ni45MjNxOC45MjMtOC45MjMgMjEuMTkyLTguODA4IDEyLjI2OS4xMTYgMjEuNTc3IDkuNDIzIDguNjkyIDkuMzA4IDguOTk5IDIxLjA3Ny4zMDggMTEuNzY5LTguOTk5IDIxLjA3Nkw1MDUuMzA3LTM1My43N3EtNS42MTUgNS42MTYtMTEuODQ2IDcuOTIzLTYuMjMgMi4zMDgtMTMuNDYxIDIuMzA4Wk0yNTIuMzA5LTE4MC4wMDFxLTMwLjMwOCAwLTUxLjMwOC0yMXQtMjEtNTEuMzA4di03OC40NjFxMC0xMi43NjkgOC42MTYtMjEuMzg0IDguNjE1LTguNjE1IDIxLjM4NC04LjYxNXQyMS4zODQgOC42MTVRMjQwLTM0My41MzkgMjQwLTMzMC43N3Y3OC40NjFxMCA0LjYxNiAzLjg0NiA4LjQ2MyAzLjg0NyAzLjg0NiA4LjQ2MyAzLjg0Nmg0NTUuMzgycTQuNjE2IDAgOC40NjMtMy44NDYgMy44NDYtMy44NDcgMy44NDYtOC40NjN2LTc4LjQ2MXEwLTEyLjc2OSA4LjYxNS0yMS4zODR0MjEuMzg0LTguNjE1cTEyLjc2OSAwIDIxLjM4NCA4LjYxNSA4LjYxNiA4LjYxNSA4LjYxNiAyMS4zODR2NzguNDYxcTAgMzAuMzA4LTIxIDUxLjMwOHQtNTEuMzA4IDIxSDI1Mi4zMDlaIi8+PC9zdmc+';
79139

140+
const triggerUploadFileNativeHandler = () => {
141+
if (fileInputElement.current) {
142+
fileInputElement.current.value = '';
143+
fileInputElement.current.click();
144+
}
145+
};
146+
147+
const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
148+
if (event.key === 'Enter' || event.key === ' ') {
149+
event.preventDefault();
150+
triggerUploadFileNativeHandler();
151+
}
152+
};
153+
80154
const handleFilesDropped = (event: React.DragEvent<HTMLDivElement>) => {
81155
event.preventDefault();
82156
setIsHover(false);
@@ -87,14 +161,6 @@ export function FileUpload<Document>({
87161
onFileDeleted(files[event.currentTarget.id]);
88162
};
89163

90-
const triggerUploadFileNativeHandler = () => {
91-
// clear file input to trigger onChange when uploading same filename
92-
if (fileInputElement.current) {
93-
fileInputElement.current.value = '';
94-
fileInputElement.current.click();
95-
}
96-
};
97-
98164
const handleFileSelected = (event: React.ChangeEvent<HTMLInputElement>) => {
99165
onFilesSelected(event.target.files);
100166
};
@@ -124,7 +190,6 @@ export function FileUpload<Document>({
124190
</div>
125191
</div>
126192
)}
127-
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
128193
<div
129194
className="ffe-file-upload__upload-section"
130195
onDrop={handleFilesDropped}
@@ -133,6 +198,10 @@ export function FileUpload<Document>({
133198
setIsHover(true);
134199
}}
135200
onDragLeave={() => setIsHover(false)}
201+
role="button"
202+
tabIndex={0}
203+
onKeyDown={handleKeyDown}
204+
aria-label={label}
136205
>
137206
<div
138207
className={classNames(

0 commit comments

Comments
 (0)