@transferwise/components 0.0.0-experimental-4fb37a3 → 0.0.0-experimental-05bf45b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -72,6 +72,15 @@ export type UploadInputProps = {
72
72
  } & Pick<UploadButtonProps, 'disabled' | 'multiple' | 'fileTypes' | 'sizeLimit' | 'description' | 'id' | 'uploadButtonTitle'> & {
73
73
  onDownload?: UploadItemProps['onDownload'];
74
74
  } & CommonProps;
75
+ /**
76
+ * The component allows users to upload files, manage the list of uploaded files,
77
+ * and handle file validation and deletion.
78
+ *
79
+ * @param {UploadInputProps} props - The properties for the UploadInput component.
80
+ *
81
+ * @see {@link UploadInput} for further information.
82
+ * @see {@link https://storybook.wise.design/?path=/docs/forms-uploadinput--docs|Storybook Wise Design}
83
+ */
75
84
  declare const UploadInput: ({ files, fileInputName, className, deleteConfirm, disabled, multiple, fileTypes, sizeLimit, description, onUploadFile, onDeleteFile, onValidationError, onFilesChange, onDownload, maxFiles, maxFilesErrorMessage, id, sizeLimitErrorMessage, uploadButtonTitle, }: UploadInputProps) => import("react").JSX.Element;
76
85
  export default UploadInput;
77
86
  //# sourceMappingURL=UploadInput.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UploadInput.d.ts","sourceRoot":"","sources":["../../../src/uploadInput/UploadInput.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAiC,MAAM,WAAW,CAAC;AAOvE,OAAO,EAAE,YAAY,EAAe,cAAc,EAAE,MAAM,SAAS,CAAC;AACpE,OAAqB,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAE9E,OAAmB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAEtE,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAEhC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;;OAIG;IACH,YAAY,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAE9D;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAErD;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAEjD;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IAEhD;;OAEG;IACH,aAAa,CAAC,EAAE;QACd;;WAEG;QACH,KAAK,CAAC,EAAE,MAAM,CAAC;QAEf;;WAEG;QACH,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;QAEvB;;WAEG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QAErB;;WAEG;QACH,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IAEF;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;OAEG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC,GAAG,IAAI,CACN,iBAAiB,EACjB,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG,WAAW,GAAG,aAAa,GAAG,IAAI,GAAG,mBAAmB,CACjG,GAAG;IAAE,UAAU,CAAC,EAAE,eAAe,CAAC,YAAY,CAAC,CAAA;CAAE,GAAG,WAAW,CAAC;AAYjE,QAAA,MAAM,WAAW,uQAoBd,gBAAgB,gCA8SlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"UploadInput.d.ts","sourceRoot":"","sources":["../../../src/uploadInput/UploadInput.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAiC,MAAM,WAAW,CAAC;AAOvE,OAAO,EAAE,YAAY,EAAe,cAAc,EAAE,MAAM,SAAS,CAAC;AACpE,OAAqB,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAE9E,OAAmB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAEtE,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAEhC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;;OAIG;IACH,YAAY,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAE9D;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAErD;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAEjD;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IAEhD;;OAEG;IACH,aAAa,CAAC,EAAE;QACd;;WAEG;QACH,KAAK,CAAC,EAAE,MAAM,CAAC;QAEf;;WAEG;QACH,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;QAEvB;;WAEG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QAErB;;WAEG;QACH,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IAEF;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;OAEG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC,GAAG,IAAI,CACN,iBAAiB,EACjB,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG,WAAW,GAAG,aAAa,GAAG,IAAI,GAAG,mBAAmB,CACjG,GAAG;IAAE,UAAU,CAAC,EAAE,eAAe,CAAC,YAAY,CAAC,CAAA;CAAE,GAAG,WAAW,CAAC;AAgCjE;;;;;;;;GAQG;AACH,QAAA,MAAM,WAAW,uQAoBd,gBAAgB,gCAsSlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -21,7 +21,9 @@ interface UploadItemRef {
21
21
  }
22
22
  export declare enum TEST_IDS {
23
23
  uploadItem = "uploadItem",
24
- mediaBody = "mediaBody"
24
+ mediaBody = "mediaBody",
25
+ link = "link",
26
+ action = "action"
25
27
  }
26
28
  declare const UploadItem: import("react").ForwardRefExoticComponent<Omit<UploadItemProps, "ref"> & import("react").RefAttributes<UploadItemRef>>;
27
29
  export default UploadItem;
@@ -1 +1 @@
1
- {"version":3,"file":"UploadItem.d.ts","sourceRoot":"","sources":["../../../../src/uploadInput/uploadItem/UploadItem.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,YAAY,EAAe,MAAM,UAAU,CAAC;AAKrD,MAAM,MAAM,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,mBAAmB,GAAG;IAC5D,IAAI,EAAE,YAAY,CAAC;IACnB;;OAEG;IACH,gBAAgB,EAAE,OAAO,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IAErB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAC1C,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;CAChC,CAAC;AAEF,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,oBAAY,QAAQ;IAClB,UAAU,eAAe;IACzB,SAAS,cAAc;CACxB;AAED,QAAA,MAAM,UAAU,wHAgJf,CAAC;AAIF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"UploadItem.d.ts","sourceRoot":"","sources":["../../../../src/uploadInput/uploadItem/UploadItem.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAe,MAAM,UAAU,CAAC;AAKrD,MAAM,MAAM,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,mBAAmB,GAAG;IAC5D,IAAI,EAAE,YAAY,CAAC;IACnB;;OAEG;IACH,gBAAgB,EAAE,OAAO,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IAErB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAC1C,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;CAChC,CAAC;AAEF,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,oBAAY,QAAQ;IAClB,UAAU,eAAe;IACzB,SAAS,cAAc;IACvB,IAAI,SAAS;IACb,MAAM,WAAW;CAClB;AAED,QAAA,MAAM,UAAU,wHAqJf,CAAC;AAIF,eAAe,UAAU,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"UploadItemLink.d.ts","sourceRoot":"","sources":["../../../../src/uploadInput/uploadItem/UploadItemLink.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,UAAU,EAAc,MAAM,OAAO,CAAC;AASlE,eAAO,MAAM,cAAc;UALnB,MAAM;iBACC,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI;sBACtB,OAAO;;;sEAyB1B,CAAC"}
1
+ {"version":3,"file":"UploadItemLink.d.ts","sourceRoot":"","sources":["../../../../src/uploadInput/uploadItem/UploadItemLink.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,UAAU,EAAc,MAAM,OAAO,CAAC;AASlE,eAAO,MAAM,cAAc;UALnB,MAAM;iBACC,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI;sBACtB,OAAO;;;sEAiC1B,CAAC"}
@@ -24,6 +24,15 @@ function generateFileId(file) {
24
24
  const uploadTimeStamp = new Date().getTime();
25
25
  return `${name}_${size}_${uploadTimeStamp}`;
26
26
  }
27
+ /**
28
+ * The component allows users to upload files, manage the list of uploaded files,
29
+ * and handle file validation and deletion.
30
+ *
31
+ * @param {UploadInputProps} props - The properties for the UploadInput component.
32
+ *
33
+ * @see {@link UploadInput} for further information.
34
+ * @see {@link https://storybook.wise.design/?path=/docs/forms-uploadinput--docs|Storybook Wise Design}
35
+ */
27
36
  const UploadInput = ({
28
37
  files = [],
29
38
  fileInputName = 'file',
@@ -49,7 +58,7 @@ const UploadInput = ({
49
58
  nonLabelable: true
50
59
  });
51
60
  const [markedFileForDelete, setMarkedFileForDelete] = React.useState(null);
52
- const [fileToRemoveIndex, setFileToRemoveIndex] = React.useState(null);
61
+ const [nextFocusItem, setNextFocusItem] = React.useState(null);
53
62
  const [mounted, setMounted] = React.useState(false);
54
63
  const {
55
64
  formatMessage
@@ -57,56 +66,73 @@ const UploadInput = ({
57
66
  const itemRefs = React.useRef([]);
58
67
  const uploadInputRef = React.useRef(null);
59
68
  const PROGRESS_STATUSES = new Set([status.Status.PENDING, status.Status.PROCESSING]);
69
+ const FOCUS_TIMEOUT = 400;
60
70
  const [uploadedFiles, setUploadedFiles] = React.useState(multiple || files.length === 0 ? files : [files[0]]);
61
71
  const uploadedFilesListReference = React.useRef(multiple || files.length === 0 ? files : [files[0]]);
72
+ function updateFileList(updateFn) {
73
+ setUploadedFiles(updateFn);
74
+ uploadedFilesListReference.current = updateFn(uploadedFilesListReference.current);
75
+ }
62
76
  function addFileToList(recentUploadedFile) {
63
- function addToList(listToAddTo) {
64
- return [...listToAddTo, recentUploadedFile];
65
- }
66
- setUploadedFiles(addToList);
67
- uploadedFilesListReference.current = addToList(uploadedFilesListReference.current);
77
+ updateFileList(list => [...list, recentUploadedFile]);
68
78
  }
69
- const removeFileFromList = file => {
70
- function filterOutFrom(listToFilterFrom) {
71
- return listToFilterFrom.filter(fileInList => file !== fileInList && file.id !== fileInList.id);
72
- }
73
- setUploadedFiles(filterOutFrom);
74
- uploadedFilesListReference.current = filterOutFrom(uploadedFilesListReference.current);
75
- };
76
- const modifyFileInList = (file, updates) => {
77
- const updateListItem = listToUpdate => listToUpdate.map(fileInList => {
78
- return fileInList === file || fileInList.id === file.id ? {
79
- ...file,
80
- ...updates
81
- } : fileInList;
79
+ function removeFileFromList(file) {
80
+ updateFileList(list => list.filter(fileInList => file !== fileInList && file.id !== fileInList.id));
81
+ }
82
+ function modifyFileInList(file, updates) {
83
+ updateFileList(list => list.map(fileInList => fileInList === file || fileInList.id === file.id ? {
84
+ ...file,
85
+ ...updates
86
+ } : fileInList));
87
+ }
88
+ function focusNextItem(focusId = null, isLastItem = false, timeout = FOCUS_TIMEOUT) {
89
+ const nextFocusIdIndex = focusId ? uploadedFilesListReference.current.findIndex(item => item.id === focusId) : -1;
90
+ requestAnimationFrame(() => {
91
+ setTimeout(() => {
92
+ if (isLastItem || nextFocusIdIndex === -1) {
93
+ // If it's the last item or no next item, focus on the upload input reference
94
+ uploadInputRef.current?.focus();
95
+ } else {
96
+ const nextFocusElement = itemRefs.current[nextFocusIdIndex];
97
+ nextFocusElement?.focus();
98
+ }
99
+ }, timeout);
82
100
  });
83
- setUploadedFiles(updateListItem);
84
- uploadedFilesListReference.current = updateListItem(uploadedFilesListReference.current);
85
- };
86
- const [fileToRemove, setFileToRemove] = React.useState(null);
101
+ }
87
102
  const removeFile = file => {
88
103
  const {
89
104
  id,
90
105
  status: status$1
91
106
  } = file;
92
107
  const index = uploadedFiles.findIndex(f => f.id === file.id);
93
- setFileToRemoveIndex(index);
108
+ const isLastItem = index === uploadedFiles.length - 1;
109
+ const nextIndexId = uploadedFiles[index + 1]?.id;
110
+ const focusId = nextIndexId ?? null;
94
111
  if (status$1 === status.Status.FAILED) {
95
112
  removeFileFromList(file);
96
- setFileToRemove(file);
113
+ setNextFocusItem({
114
+ focusId: focusId ?? null,
115
+ isLastItem
116
+ });
97
117
  } else if (onDeleteFile && id) {
98
118
  modifyFileInList(file, {
99
119
  status: status.Status.PROCESSING,
100
120
  error: undefined
101
121
  });
122
+ setNextFocusItem({
123
+ focusId,
124
+ isLastItem
125
+ });
102
126
  onDeleteFile(id).then(() => {
103
127
  removeFileFromList(file);
104
128
  }).catch(error => {
105
129
  modifyFileInList(file, {
106
130
  error: error
107
131
  });
108
- }).finally(() => {
109
- setFileToRemove(file);
132
+ setNextFocusItem({
133
+ focusId,
134
+ isLastItem
135
+ });
110
136
  });
111
137
  }
112
138
  };
@@ -138,22 +164,17 @@ const UploadInput = ({
138
164
  const numberOfValidFiles = getNumberOfFilesUploaded();
139
165
  return numberOfValidFiles >= maxFiles;
140
166
  }
141
- // One or more files selected, create entries for them
142
167
  const addFiles = selectedFiles => {
143
168
  for (let i = 0; i < selectedFiles.length; i += 1) {
144
169
  const file = selectedFiles.item(i);
145
- // Returning a FormData[] array instead of FileList so we can filter out incorrect files
146
170
  const formData = new FormData();
147
171
  if (file) {
148
172
  generateFileId(file);
149
173
  const allowedFileTypes = typeof fileTypes === 'string' ? fileTypes : fileTypes.join(',');
150
- // Check if file type is valid
151
174
  if (!isTypeValid.isTypeValid(file, allowedFileTypes)) {
152
175
  handleFileUploadFailure(file, formatMessage(UploadInput_messages.fileTypeNotSupported));
153
176
  continue;
154
177
  }
155
- // Check if the filesize is valid
156
- // Convert to rough bytes
157
178
  if (!isSizeValid.isSizeValid(file, sizeLimit * 1000)) {
158
179
  const failureMessage = sizeLimitErrorMessage || formatMessage(UploadInput_messages.fileIsTooLarge);
159
180
  handleFileUploadFailure(file, failureMessage);
@@ -166,13 +187,10 @@ const UploadInput = ({
166
187
  handleFileUploadFailure(file, failureMessage);
167
188
  continue;
168
189
  }
169
- // Check if the file is already in the list
170
190
  const existingFile = uploadedFiles.find(f => f.filename === file.name);
171
191
  if (existingFile) {
172
- // Remove the file from the list before adding it again
173
192
  removeFileFromList(existingFile);
174
193
  }
175
- // Add the file to the list
176
194
  formData.append(fileInputName, file);
177
195
  const pendingFile = {
178
196
  id: generateFileId(file),
@@ -180,13 +198,11 @@ const UploadInput = ({
180
198
  status: status.Status.PENDING
181
199
  };
182
200
  addFileToList(pendingFile);
183
- // Start uploading the file
184
201
  onUploadFile(formData).then(({
185
202
  id,
186
203
  url,
187
204
  error
188
205
  }) => {
189
- // Replace the temporary id with the final one received from the API, and also set any errors
190
206
  modifyFileInList(pendingFile, {
191
207
  id,
192
208
  url,
@@ -200,27 +216,17 @@ const UploadInput = ({
200
216
  });
201
217
  });
202
218
  if (!multiple) {
203
- // Only upload a single file
204
219
  break;
205
220
  }
206
221
  }
207
222
  }
208
223
  };
209
224
  React.useLayoutEffect(() => {
210
- if (fileToRemove && fileToRemoveIndex !== null) {
211
- requestAnimationFrame(() => {
212
- const nextFocusIndex = Math.min(fileToRemoveIndex, uploadedFiles.length - 1);
213
- if (itemRefs.current[nextFocusIndex]) {
214
- itemRefs.current[nextFocusIndex].focus(); // Focus the next UploadItem
215
- } else {
216
- // If there's only one item left, focus the UploadButton
217
- uploadInputRef.current?.focus();
218
- }
219
- });
220
- setFileToRemove(null); // Reset the state
221
- setFileToRemoveIndex(null); // Reset the index
225
+ if (nextFocusItem) {
226
+ focusNextItem(nextFocusItem.focusId, nextFocusItem.isLastItem);
222
227
  }
223
- }, [uploadedFiles, fileToRemove, fileToRemoveIndex, itemRefs, uploadInputRef]);
228
+ setNextFocusItem(null);
229
+ }, [nextFocusItem]);
224
230
  React.useEffect(() => {
225
231
  setMounted(true);
226
232
  }, []);
@@ -1 +1 @@
1
- {"version":3,"file":"UploadInput.js","sources":["../../src/uploadInput/UploadInput.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport { useEffect, useRef, useState, useLayoutEffect } from 'react';\nimport { useIntl } from 'react-intl';\n\nimport Button from '../button';\nimport { CommonProps, ControlType, Priority, Status } from '../common';\nimport { useInputAttributes } from '../inputs/contexts';\nimport Modal from '../modal';\nimport { isSizeValid } from '../upload/utils/isSizeValid';\nimport { isTypeValid } from '../upload/utils/isTypeValid';\n\nimport MESSAGES from './UploadInput.messages';\nimport { UploadedFile, UploadError, UploadResponse } from './types';\nimport UploadButton, { UploadButtonProps } from './uploadButton/UploadButton';\nimport { DEFAULT_SIZE_LIMIT, imageFileTypes } from './uploadButton/defaults';\nimport UploadItem, { UploadItemProps } from './uploadItem/UploadItem';\n\nexport type UploadInputProps = {\n /**\n * List of already existing, failed or in progress files\n */\n files?: readonly UploadedFile[];\n\n /**\n * The key of the file in the returned FormData object (default: file)\n */\n fileInputName?: string;\n\n /**\n * Callback that handles form submission\n *\n * @param formData\n */\n onUploadFile: (formData: FormData) => Promise<UploadResponse>;\n\n /**\n * Provide a callback if the file can be removed/deleted from the server\n * Your app is responsible for reloading the uploaded files list and updating the component to ensure that the file has in fact been deleted successfully\n *\n * @param id\n */\n onDeleteFile?: (id: string | number) => Promise<any>;\n\n /**\n * Provide a callback to trigger on validation error\n *\n * @param file\n */\n onValidationError?: (file: UploadedFile) => void;\n\n /**\n * Provide a callback to trigger on change whenever the files are updated\n *\n * @param files\n */\n onFilesChange?: (files: UploadedFile[]) => void;\n\n /**\n * Confirmation modal displayed on delete\n */\n deleteConfirm?: {\n /**\n * The title of the confirmation modal on delete\n */\n title?: string;\n\n /**\n * The body of the confirmation modal on delete\n */\n body?: React.ReactNode;\n\n /**\n * The confirm button text of the confirmation modal on delete\n */\n confirmText?: string;\n\n /**\n * The cancel button text of the confirmation modal on delete\n */\n cancelText?: string;\n };\n\n /**\n * Maximum number of files allowed, if provided, shows error below file item\n */\n maxFiles?: number;\n\n /**\n * Error message to show when the maximum number of files are uploaded already\n */\n maxFilesErrorMessage?: string;\n\n /**\n * Error message to show when files over a allowed size limit are uploaded\n */\n sizeLimitErrorMessage?: string;\n} & Pick<\n UploadButtonProps,\n 'disabled' | 'multiple' | 'fileTypes' | 'sizeLimit' | 'description' | 'id' | 'uploadButtonTitle'\n> & { onDownload?: UploadItemProps['onDownload'] } & CommonProps;\n\ninterface UploadItemRef {\n focus: () => void;\n}\n\nfunction generateFileId(file: File) {\n const { name, size } = file;\n const uploadTimeStamp = new Date().getTime();\n return `${name}_${size}_${uploadTimeStamp}`;\n}\n\nconst UploadInput = ({\n files = [],\n fileInputName = 'file',\n className,\n deleteConfirm,\n disabled,\n multiple = false,\n fileTypes = imageFileTypes,\n sizeLimit = DEFAULT_SIZE_LIMIT,\n description,\n onUploadFile,\n onDeleteFile,\n onValidationError,\n onFilesChange,\n onDownload,\n maxFiles,\n maxFilesErrorMessage,\n id,\n sizeLimitErrorMessage,\n uploadButtonTitle,\n}: UploadInputProps) => {\n const inputAttributes = useInputAttributes({ nonLabelable: true });\n\n const [markedFileForDelete, setMarkedFileForDelete] = useState<UploadedFile | null>(null);\n const [fileToRemoveIndex, setFileToRemoveIndex] = useState<number | null>(null);\n const [mounted, setMounted] = useState(false);\n const { formatMessage } = useIntl();\n const itemRefs = useRef<(HTMLDivElement | UploadItemRef | null)[]>([]);\n const uploadInputRef = useRef<HTMLInputElement | null>(null);\n\n const PROGRESS_STATUSES = new Set([Status.PENDING, Status.PROCESSING]);\n\n const [uploadedFiles, setUploadedFiles] = useState<readonly UploadedFile[]>(\n multiple || files.length === 0 ? files : [files[0]],\n );\n\n const uploadedFilesListReference = useRef(multiple || files.length === 0 ? files : [files[0]]);\n\n function addFileToList(recentUploadedFile: UploadedFile) {\n function addToList(listToAddTo: readonly UploadedFile[]) {\n return [...listToAddTo, recentUploadedFile];\n }\n\n setUploadedFiles(addToList);\n uploadedFilesListReference.current = addToList(uploadedFilesListReference.current);\n }\n\n const removeFileFromList = (file: UploadedFile) => {\n function filterOutFrom(listToFilterFrom: readonly UploadedFile[]) {\n return listToFilterFrom.filter(\n (fileInList) => file !== fileInList && file.id !== fileInList.id,\n );\n }\n\n setUploadedFiles(filterOutFrom);\n uploadedFilesListReference.current = filterOutFrom(uploadedFilesListReference.current);\n };\n\n const modifyFileInList = (file: UploadedFile, updates: Partial<UploadedFile>) => {\n const updateListItem = (listToUpdate: readonly UploadedFile[]) =>\n listToUpdate.map((fileInList) => {\n return fileInList === file || fileInList.id === file.id\n ? { ...file, ...updates }\n : fileInList;\n });\n\n setUploadedFiles(updateListItem);\n uploadedFilesListReference.current = updateListItem(uploadedFilesListReference.current);\n };\n\n const [fileToRemove, setFileToRemove] = useState<UploadedFile | null>(null);\n\n const removeFile = (file: UploadedFile) => {\n const { id, status } = file;\n const index = uploadedFiles.findIndex((f) => f.id === file.id);\n setFileToRemoveIndex(index);\n\n if (status === Status.FAILED) {\n removeFileFromList(file);\n setFileToRemove(file);\n } else if (onDeleteFile && id) {\n modifyFileInList(file, { status: Status.PROCESSING, error: undefined });\n\n onDeleteFile(id)\n .then(() => {\n removeFileFromList(file);\n })\n .catch((error) => {\n modifyFileInList(file, { error: error as UploadError });\n })\n .finally(() => {\n setFileToRemove(file);\n });\n }\n };\n\n function handleFileUploadFailure(file: File, failureMessage: string) {\n const { name } = file;\n const id = generateFileId(file);\n const failedUpload = {\n id,\n filename: name,\n status: Status.FAILED,\n error: failureMessage,\n };\n\n addFileToList(failedUpload);\n\n if (onValidationError) {\n onValidationError(failedUpload);\n }\n }\n\n function getNumberOfFilesUploaded() {\n const uploadInitiatedStatus = new Set([Status.SUCCEEDED, Status.PENDING]);\n const validFiles = uploadedFilesListReference.current.filter(\n (file) => file.status && uploadInitiatedStatus.has(file.status),\n );\n return validFiles.length;\n }\n\n function areMaximumFilesUploadedAlready() {\n if (!maxFiles) {\n return false;\n }\n\n const numberOfValidFiles = getNumberOfFilesUploaded();\n return numberOfValidFiles >= maxFiles;\n }\n\n // One or more files selected, create entries for them\n const addFiles = (selectedFiles: FileList) => {\n for (let i = 0; i < selectedFiles.length; i += 1) {\n const file = selectedFiles.item(i);\n\n // Returning a FormData[] array instead of FileList so we can filter out incorrect files\n const formData = new FormData();\n\n if (file) {\n const { name } = file;\n const id = generateFileId(file);\n\n const allowedFileTypes = typeof fileTypes === 'string' ? fileTypes : fileTypes.join(',');\n\n // Check if file type is valid\n if (!isTypeValid(file, allowedFileTypes)) {\n handleFileUploadFailure(file, formatMessage(MESSAGES.fileTypeNotSupported));\n continue;\n }\n\n // Check if the filesize is valid\n // Convert to rough bytes\n if (!isSizeValid(file, sizeLimit * 1000)) {\n const failureMessage = sizeLimitErrorMessage || formatMessage(MESSAGES.fileIsTooLarge);\n handleFileUploadFailure(file, failureMessage);\n continue;\n }\n\n if (areMaximumFilesUploadedAlready()) {\n const failureMessage =\n maxFilesErrorMessage ||\n formatMessage(MESSAGES.maximumFilesAlreadyUploaded, { maxFilesAllowed: maxFiles });\n handleFileUploadFailure(file, failureMessage);\n continue;\n }\n\n // Check if the file is already in the list\n const existingFile = uploadedFiles.find((f) => f.filename === file.name);\n if (existingFile) {\n // Remove the file from the list before adding it again\n removeFileFromList(existingFile);\n }\n\n // Add the file to the list\n formData.append(fileInputName, file);\n const pendingFile = {\n id: generateFileId(file),\n filename: file.name,\n status: Status.PENDING,\n };\n\n addFileToList(pendingFile);\n\n // Start uploading the file\n onUploadFile(formData)\n .then(({ id, url, error }: UploadResponse) => {\n // Replace the temporary id with the final one received from the API, and also set any errors\n modifyFileInList(pendingFile, { id, url, error, status: Status.SUCCEEDED });\n })\n .catch((error) => {\n modifyFileInList(pendingFile, { error: error as UploadError, status: Status.FAILED });\n });\n\n if (!multiple) {\n // Only upload a single file\n break;\n }\n }\n }\n };\n\n useLayoutEffect(() => {\n if (fileToRemove && fileToRemoveIndex !== null) {\n requestAnimationFrame(() => {\n const nextFocusIndex = Math.min(fileToRemoveIndex, uploadedFiles.length - 1);\n if (itemRefs.current[nextFocusIndex]) {\n itemRefs.current[nextFocusIndex].focus(); // Focus the next UploadItem\n } else {\n // If there's only one item left, focus the UploadButton\n uploadInputRef.current?.focus();\n }\n });\n setFileToRemove(null); // Reset the state\n setFileToRemoveIndex(null); // Reset the index\n }\n }, [uploadedFiles, fileToRemove, fileToRemoveIndex, itemRefs, uploadInputRef]);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (onFilesChange && mounted) {\n onFilesChange([...uploadedFiles]);\n }\n }, [onFilesChange, uploadedFiles]); // eslint-disable-line react-hooks/exhaustive-deps\n\n return (\n <>\n <div\n role=\"group\"\n className={clsx('np-upload-input', className, { disabled })}\n {...inputAttributes}\n >\n <div\n className=\"np-upload-input__section\"\n aria-live=\"polite\"\n aria-relevant=\"all\"\n role=\"region\"\n >\n {uploadedFiles.map((file, index) => (\n <UploadItem\n key={file.id}\n ref={(el: UploadItemRef | null) => {\n itemRefs.current[index] = el;\n }}\n file={file}\n singleFileUpload={!multiple}\n canDelete={\n (!!onDeleteFile || file.status === Status.FAILED) &&\n (!file.status || !PROGRESS_STATUSES.has(file.status))\n }\n onDelete={\n file.status === Status.FAILED\n ? () => removeFile(file)\n : () => setMarkedFileForDelete(file)\n }\n onDownload={onDownload}\n />\n ))}\n </div>\n {(multiple || (!multiple && !uploadedFiles.length)) && (\n <div className=\"np-upload-input__section np-upload-input__section--uploader\">\n <UploadButton\n ref={uploadInputRef}\n id={id}\n uploadButtonTitle={uploadButtonTitle}\n disabled={areMaximumFilesUploadedAlready() || disabled}\n multiple={multiple}\n fileTypes={fileTypes}\n sizeLimit={sizeLimit}\n description={description}\n maxFiles={maxFiles}\n withEntries={Boolean(uploadedFiles.length)}\n onChange={addFiles}\n />\n </div>\n )}\n </div>\n <Modal\n title={\n deleteConfirm?.title !== undefined\n ? deleteConfirm.title\n : formatMessage(MESSAGES.deleteModalTitle)\n }\n body={\n deleteConfirm?.body !== undefined\n ? deleteConfirm.body\n : formatMessage(MESSAGES.deleteModalBody)\n }\n open={!!markedFileForDelete}\n footer={\n <>\n <Button\n block\n onClick={() => {\n setMarkedFileForDelete(null);\n }}\n >\n {deleteConfirm?.cancelText || formatMessage(MESSAGES.deleteModalCancelButtonText)}\n </Button>\n <Button\n block\n priority={Priority.SECONDARY}\n type={ControlType.NEGATIVE}\n onClick={() => {\n if (markedFileForDelete) {\n removeFile(markedFileForDelete);\n }\n setMarkedFileForDelete(null);\n }}\n >\n {deleteConfirm?.confirmText || formatMessage(MESSAGES.deleteModalConfirmButtonText)}\n </Button>\n </>\n }\n onClose={() => {\n setMarkedFileForDelete(null);\n }}\n />\n </>\n );\n};\n\nexport default UploadInput;\n"],"names":["generateFileId","file","name","size","uploadTimeStamp","Date","getTime","UploadInput","files","fileInputName","className","deleteConfirm","disabled","multiple","fileTypes","imageFileTypes","sizeLimit","DEFAULT_SIZE_LIMIT","description","onUploadFile","onDeleteFile","onValidationError","onFilesChange","onDownload","maxFiles","maxFilesErrorMessage","id","sizeLimitErrorMessage","uploadButtonTitle","inputAttributes","useInputAttributes","nonLabelable","markedFileForDelete","setMarkedFileForDelete","useState","fileToRemoveIndex","setFileToRemoveIndex","mounted","setMounted","formatMessage","useIntl","itemRefs","useRef","uploadInputRef","PROGRESS_STATUSES","Set","Status","PENDING","PROCESSING","uploadedFiles","setUploadedFiles","length","uploadedFilesListReference","addFileToList","recentUploadedFile","addToList","listToAddTo","current","removeFileFromList","filterOutFrom","listToFilterFrom","filter","fileInList","modifyFileInList","updates","updateListItem","listToUpdate","map","fileToRemove","setFileToRemove","removeFile","status","index","findIndex","f","FAILED","error","undefined","then","catch","finally","handleFileUploadFailure","failureMessage","failedUpload","filename","getNumberOfFilesUploaded","uploadInitiatedStatus","SUCCEEDED","validFiles","has","areMaximumFilesUploadedAlready","numberOfValidFiles","addFiles","selectedFiles","i","item","formData","FormData","allowedFileTypes","join","isTypeValid","MESSAGES","fileTypeNotSupported","isSizeValid","fileIsTooLarge","maximumFilesAlreadyUploaded","maxFilesAllowed","existingFile","find","append","pendingFile","url","useLayoutEffect","requestAnimationFrame","nextFocusIndex","Math","min","focus","useEffect","_jsxs","_Fragment","children","role","clsx","_jsx","UploadItem","ref","el","singleFileUpload","canDelete","onDelete","UploadButton","withEntries","Boolean","onChange","Modal","title","deleteModalTitle","body","deleteModalBody","open","footer","Button","block","onClick","cancelText","deleteModalCancelButtonText","priority","Priority","SECONDARY","type","ControlType","NEGATIVE","confirmText","deleteModalConfirmButtonText","onClose"],"mappings":"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"}
1
+ {"version":3,"file":"UploadInput.js","sources":["../../src/uploadInput/UploadInput.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport { useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport { useIntl } from 'react-intl';\n\nimport Button from '../button';\nimport { CommonProps, ControlType, Priority, Status } from '../common';\nimport { useInputAttributes } from '../inputs/contexts';\nimport Modal from '../modal';\nimport { isSizeValid } from '../upload/utils/isSizeValid';\nimport { isTypeValid } from '../upload/utils/isTypeValid';\n\nimport MESSAGES from './UploadInput.messages';\nimport { UploadedFile, UploadError, UploadResponse } from './types';\nimport UploadButton, { UploadButtonProps } from './uploadButton/UploadButton';\nimport { DEFAULT_SIZE_LIMIT, imageFileTypes } from './uploadButton/defaults';\nimport UploadItem, { UploadItemProps } from './uploadItem/UploadItem';\n\nexport type UploadInputProps = {\n /**\n * List of already existing, failed or in progress files\n */\n files?: readonly UploadedFile[];\n\n /**\n * The key of the file in the returned FormData object (default: file)\n */\n fileInputName?: string;\n\n /**\n * Callback that handles form submission\n *\n * @param formData\n */\n onUploadFile: (formData: FormData) => Promise<UploadResponse>;\n\n /**\n * Provide a callback if the file can be removed/deleted from the server\n * Your app is responsible for reloading the uploaded files list and updating the component to ensure that the file has in fact been deleted successfully\n *\n * @param id\n */\n onDeleteFile?: (id: string | number) => Promise<any>;\n\n /**\n * Provide a callback to trigger on validation error\n *\n * @param file\n */\n onValidationError?: (file: UploadedFile) => void;\n\n /**\n * Provide a callback to trigger on change whenever the files are updated\n *\n * @param files\n */\n onFilesChange?: (files: UploadedFile[]) => void;\n\n /**\n * Confirmation modal displayed on delete\n */\n deleteConfirm?: {\n /**\n * The title of the confirmation modal on delete\n */\n title?: string;\n\n /**\n * The body of the confirmation modal on delete\n */\n body?: React.ReactNode;\n\n /**\n * The confirm button text of the confirmation modal on delete\n */\n confirmText?: string;\n\n /**\n * The cancel button text of the confirmation modal on delete\n */\n cancelText?: string;\n };\n\n /**\n * Maximum number of files allowed, if provided, shows error below file item\n */\n maxFiles?: number;\n\n /**\n * Error message to show when the maximum number of files are uploaded already\n */\n maxFilesErrorMessage?: string;\n\n /**\n * Error message to show when files over a allowed size limit are uploaded\n */\n sizeLimitErrorMessage?: string;\n} & Pick<\n UploadButtonProps,\n 'disabled' | 'multiple' | 'fileTypes' | 'sizeLimit' | 'description' | 'id' | 'uploadButtonTitle'\n> & { onDownload?: UploadItemProps['onDownload'] } & CommonProps;\n\n/**\n * Interface representing a reference to an UploadItem component.\n * Provides a method to focus the UploadItem.\n */\ninterface UploadItemRef {\n /**\n * Focuses the UploadItem component.\n */\n focus: () => void;\n}\n\n/**\n * Represents the next item to focus on after an action is performed.\n */\ntype NextFocusItem = {\n /** The ID of the next item to focus on. If null, no specific item is targeted. */\n focusId: number | null;\n /** Indicates if the next item to focus on is the last item in the list. */\n isLastItem: boolean;\n};\n\n/**\n * Generates a unique ID for a file based on its name, size, and the current timestamp\n */\nfunction generateFileId(file: File) {\n const { name, size } = file;\n const uploadTimeStamp = new Date().getTime();\n return `${name}_${size}_${uploadTimeStamp}`;\n}\n\n/**\n * The component allows users to upload files, manage the list of uploaded files,\n * and handle file validation and deletion.\n *\n * @param {UploadInputProps} props - The properties for the UploadInput component.\n *\n * @see {@link UploadInput} for further information.\n * @see {@link https://storybook.wise.design/?path=/docs/forms-uploadinput--docs|Storybook Wise Design}\n */\nconst UploadInput = ({\n files = [],\n fileInputName = 'file',\n className,\n deleteConfirm,\n disabled,\n multiple = false,\n fileTypes = imageFileTypes,\n sizeLimit = DEFAULT_SIZE_LIMIT,\n description,\n onUploadFile,\n onDeleteFile,\n onValidationError,\n onFilesChange,\n onDownload,\n maxFiles,\n maxFilesErrorMessage,\n id,\n sizeLimitErrorMessage,\n uploadButtonTitle,\n}: UploadInputProps) => {\n const inputAttributes = useInputAttributes({ nonLabelable: true });\n const [markedFileForDelete, setMarkedFileForDelete] = useState<UploadedFile | null>(null);\n const [nextFocusItem, setNextFocusItem] = useState<NextFocusItem | null>(null);\n const [mounted, setMounted] = useState(false);\n const { formatMessage } = useIntl();\n const itemRefs = useRef<(HTMLDivElement | UploadItemRef | null)[]>([]);\n const uploadInputRef = useRef<HTMLInputElement | null>(null);\n\n const PROGRESS_STATUSES = new Set([Status.PENDING, Status.PROCESSING]);\n const FOCUS_TIMEOUT = 400;\n\n const [uploadedFiles, setUploadedFiles] = useState<readonly UploadedFile[]>(\n multiple || files.length === 0 ? files : [files[0]],\n );\n\n const uploadedFilesListReference = useRef(multiple || files.length === 0 ? files : [files[0]]);\n\n function updateFileList(updateFn: (list: readonly UploadedFile[]) => readonly UploadedFile[]) {\n setUploadedFiles(updateFn);\n uploadedFilesListReference.current = updateFn(uploadedFilesListReference.current);\n }\n\n function addFileToList(recentUploadedFile: UploadedFile) {\n updateFileList((list) => [...list, recentUploadedFile]);\n }\n\n function removeFileFromList(file: UploadedFile) {\n updateFileList((list) =>\n list.filter((fileInList) => file !== fileInList && file.id !== fileInList.id),\n );\n }\n\n function modifyFileInList(file: UploadedFile, updates: Partial<UploadedFile>) {\n updateFileList((list) =>\n list.map((fileInList) =>\n fileInList === file || fileInList.id === file.id ? { ...file, ...updates } : fileInList,\n ),\n );\n }\n\n function focusNextItem(\n focusId: number | null = null,\n isLastItem = false,\n timeout: number = FOCUS_TIMEOUT,\n ) {\n const nextFocusIdIndex = focusId\n ? uploadedFilesListReference.current.findIndex((item: UploadedFile) => item.id === focusId)\n : -1;\n\n requestAnimationFrame(() => {\n setTimeout(() => {\n if (isLastItem || nextFocusIdIndex === -1) {\n // If it's the last item or no next item, focus on the upload input reference\n uploadInputRef.current?.focus();\n } else {\n const nextFocusElement = itemRefs.current[nextFocusIdIndex];\n nextFocusElement?.focus();\n }\n }, timeout);\n });\n }\n\n const removeFile = (file: UploadedFile) => {\n const { id, status } = file;\n const index = uploadedFiles.findIndex((f) => f.id === file.id);\n const isLastItem = index === uploadedFiles.length - 1;\n const nextIndexId = uploadedFiles[index + 1]?.id as number;\n const focusId = nextIndexId ?? null;\n\n if (status === Status.FAILED) {\n removeFileFromList(file);\n setNextFocusItem({ focusId: focusId ?? null, isLastItem });\n } else if (onDeleteFile && id) {\n modifyFileInList(file, { status: Status.PROCESSING, error: undefined });\n setNextFocusItem({ focusId, isLastItem });\n\n onDeleteFile(id)\n .then(() => {\n removeFileFromList(file);\n })\n .catch((error) => {\n modifyFileInList(file, { error: error as UploadError });\n setNextFocusItem({ focusId, isLastItem });\n });\n }\n };\n\n function handleFileUploadFailure(file: File, failureMessage: string) {\n const { name } = file;\n const id = generateFileId(file);\n const failedUpload = {\n id,\n filename: name,\n status: Status.FAILED,\n error: failureMessage,\n };\n\n addFileToList(failedUpload);\n\n if (onValidationError) {\n onValidationError(failedUpload);\n }\n }\n\n function getNumberOfFilesUploaded() {\n const uploadInitiatedStatus = new Set([Status.SUCCEEDED, Status.PENDING]);\n const validFiles = uploadedFilesListReference.current.filter(\n (file) => file.status && uploadInitiatedStatus.has(file.status),\n );\n return validFiles.length;\n }\n\n function areMaximumFilesUploadedAlready() {\n if (!maxFiles) {\n return false;\n }\n\n const numberOfValidFiles = getNumberOfFilesUploaded();\n return numberOfValidFiles >= maxFiles;\n }\n\n const addFiles = (selectedFiles: FileList) => {\n for (let i = 0; i < selectedFiles.length; i += 1) {\n const file = selectedFiles.item(i);\n\n const formData = new FormData();\n\n if (file) {\n const { name } = file;\n const id = generateFileId(file);\n\n const allowedFileTypes = typeof fileTypes === 'string' ? fileTypes : fileTypes.join(',');\n\n if (!isTypeValid(file, allowedFileTypes)) {\n handleFileUploadFailure(file, formatMessage(MESSAGES.fileTypeNotSupported));\n continue;\n }\n\n if (!isSizeValid(file, sizeLimit * 1000)) {\n const failureMessage = sizeLimitErrorMessage || formatMessage(MESSAGES.fileIsTooLarge);\n handleFileUploadFailure(file, failureMessage);\n continue;\n }\n\n if (areMaximumFilesUploadedAlready()) {\n const failureMessage =\n maxFilesErrorMessage ||\n formatMessage(MESSAGES.maximumFilesAlreadyUploaded, { maxFilesAllowed: maxFiles });\n handleFileUploadFailure(file, failureMessage);\n continue;\n }\n\n const existingFile = uploadedFiles.find((f) => f.filename === file.name);\n if (existingFile) {\n removeFileFromList(existingFile);\n }\n\n formData.append(fileInputName, file);\n const pendingFile = {\n id: generateFileId(file),\n filename: file.name,\n status: Status.PENDING,\n };\n\n addFileToList(pendingFile);\n\n onUploadFile(formData)\n .then(({ id, url, error }: UploadResponse) => {\n modifyFileInList(pendingFile, { id, url, error, status: Status.SUCCEEDED });\n })\n .catch((error) => {\n modifyFileInList(pendingFile, { error: error as UploadError, status: Status.FAILED });\n });\n\n if (!multiple) {\n break;\n }\n }\n }\n };\n\n useLayoutEffect(() => {\n if (nextFocusItem) {\n focusNextItem(nextFocusItem.focusId, nextFocusItem.isLastItem);\n }\n setNextFocusItem(null);\n }, [nextFocusItem]);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (onFilesChange && mounted) {\n onFilesChange([...uploadedFiles]);\n }\n }, [onFilesChange, uploadedFiles]); // eslint-disable-line react-hooks/exhaustive-deps\n\n return (\n <>\n <div\n role=\"group\"\n className={clsx('np-upload-input', className, { disabled })}\n {...inputAttributes}\n >\n <div\n className=\"np-upload-input__section\"\n aria-live=\"polite\"\n aria-relevant=\"all\"\n role=\"region\"\n >\n {uploadedFiles.map((file, index) => (\n <UploadItem\n key={file.id}\n ref={(el: UploadItemRef | null) => {\n itemRefs.current[index] = el;\n }}\n file={file}\n singleFileUpload={!multiple}\n canDelete={\n (!!onDeleteFile || file.status === Status.FAILED) &&\n (!file.status || !PROGRESS_STATUSES.has(file.status))\n }\n onDelete={\n file.status === Status.FAILED\n ? () => removeFile(file)\n : () => setMarkedFileForDelete(file)\n }\n onDownload={onDownload}\n />\n ))}\n </div>\n {(multiple || (!multiple && !uploadedFiles.length)) && (\n <div className=\"np-upload-input__section np-upload-input__section--uploader\">\n <UploadButton\n ref={uploadInputRef}\n id={id}\n uploadButtonTitle={uploadButtonTitle}\n disabled={areMaximumFilesUploadedAlready() || disabled}\n multiple={multiple}\n fileTypes={fileTypes}\n sizeLimit={sizeLimit}\n description={description}\n maxFiles={maxFiles}\n withEntries={Boolean(uploadedFiles.length)}\n onChange={addFiles}\n />\n </div>\n )}\n </div>\n <Modal\n title={\n deleteConfirm?.title !== undefined\n ? deleteConfirm.title\n : formatMessage(MESSAGES.deleteModalTitle)\n }\n body={\n deleteConfirm?.body !== undefined\n ? deleteConfirm.body\n : formatMessage(MESSAGES.deleteModalBody)\n }\n open={!!markedFileForDelete}\n footer={\n <>\n <Button\n block\n onClick={() => {\n setMarkedFileForDelete(null);\n }}\n >\n {deleteConfirm?.cancelText || formatMessage(MESSAGES.deleteModalCancelButtonText)}\n </Button>\n <Button\n block\n priority={Priority.SECONDARY}\n type={ControlType.NEGATIVE}\n onClick={() => {\n if (markedFileForDelete) {\n removeFile(markedFileForDelete);\n }\n setMarkedFileForDelete(null);\n }}\n >\n {deleteConfirm?.confirmText || formatMessage(MESSAGES.deleteModalConfirmButtonText)}\n </Button>\n </>\n }\n onClose={() => {\n setMarkedFileForDelete(null);\n }}\n />\n </>\n );\n};\n\nexport default UploadInput;\n"],"names":["generateFileId","file","name","size","uploadTimeStamp","Date","getTime","UploadInput","files","fileInputName","className","deleteConfirm","disabled","multiple","fileTypes","imageFileTypes","sizeLimit","DEFAULT_SIZE_LIMIT","description","onUploadFile","onDeleteFile","onValidationError","onFilesChange","onDownload","maxFiles","maxFilesErrorMessage","id","sizeLimitErrorMessage","uploadButtonTitle","inputAttributes","useInputAttributes","nonLabelable","markedFileForDelete","setMarkedFileForDelete","useState","nextFocusItem","setNextFocusItem","mounted","setMounted","formatMessage","useIntl","itemRefs","useRef","uploadInputRef","PROGRESS_STATUSES","Set","Status","PENDING","PROCESSING","FOCUS_TIMEOUT","uploadedFiles","setUploadedFiles","length","uploadedFilesListReference","updateFileList","updateFn","current","addFileToList","recentUploadedFile","list","removeFileFromList","filter","fileInList","modifyFileInList","updates","map","focusNextItem","focusId","isLastItem","timeout","nextFocusIdIndex","findIndex","item","requestAnimationFrame","setTimeout","focus","nextFocusElement","removeFile","status","index","f","nextIndexId","FAILED","error","undefined","then","catch","handleFileUploadFailure","failureMessage","failedUpload","filename","getNumberOfFilesUploaded","uploadInitiatedStatus","SUCCEEDED","validFiles","has","areMaximumFilesUploadedAlready","numberOfValidFiles","addFiles","selectedFiles","i","formData","FormData","allowedFileTypes","join","isTypeValid","MESSAGES","fileTypeNotSupported","isSizeValid","fileIsTooLarge","maximumFilesAlreadyUploaded","maxFilesAllowed","existingFile","find","append","pendingFile","url","useLayoutEffect","useEffect","_jsxs","_Fragment","children","role","clsx","_jsx","UploadItem","ref","el","singleFileUpload","canDelete","onDelete","UploadButton","withEntries","Boolean","onChange","Modal","title","deleteModalTitle","body","deleteModalBody","open","footer","Button","block","onClick","cancelText","deleteModalCancelButtonText","priority","Priority","SECONDARY","type","ControlType","NEGATIVE","confirmText","deleteModalConfirmButtonText","onClose"],"mappings":"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"}
@@ -22,6 +22,15 @@ function generateFileId(file) {
22
22
  const uploadTimeStamp = new Date().getTime();
23
23
  return `${name}_${size}_${uploadTimeStamp}`;
24
24
  }
25
+ /**
26
+ * The component allows users to upload files, manage the list of uploaded files,
27
+ * and handle file validation and deletion.
28
+ *
29
+ * @param {UploadInputProps} props - The properties for the UploadInput component.
30
+ *
31
+ * @see {@link UploadInput} for further information.
32
+ * @see {@link https://storybook.wise.design/?path=/docs/forms-uploadinput--docs|Storybook Wise Design}
33
+ */
25
34
  const UploadInput = ({
26
35
  files = [],
27
36
  fileInputName = 'file',
@@ -47,7 +56,7 @@ const UploadInput = ({
47
56
  nonLabelable: true
48
57
  });
49
58
  const [markedFileForDelete, setMarkedFileForDelete] = useState(null);
50
- const [fileToRemoveIndex, setFileToRemoveIndex] = useState(null);
59
+ const [nextFocusItem, setNextFocusItem] = useState(null);
51
60
  const [mounted, setMounted] = useState(false);
52
61
  const {
53
62
  formatMessage
@@ -55,56 +64,73 @@ const UploadInput = ({
55
64
  const itemRefs = useRef([]);
56
65
  const uploadInputRef = useRef(null);
57
66
  const PROGRESS_STATUSES = new Set([Status.PENDING, Status.PROCESSING]);
67
+ const FOCUS_TIMEOUT = 400;
58
68
  const [uploadedFiles, setUploadedFiles] = useState(multiple || files.length === 0 ? files : [files[0]]);
59
69
  const uploadedFilesListReference = useRef(multiple || files.length === 0 ? files : [files[0]]);
70
+ function updateFileList(updateFn) {
71
+ setUploadedFiles(updateFn);
72
+ uploadedFilesListReference.current = updateFn(uploadedFilesListReference.current);
73
+ }
60
74
  function addFileToList(recentUploadedFile) {
61
- function addToList(listToAddTo) {
62
- return [...listToAddTo, recentUploadedFile];
63
- }
64
- setUploadedFiles(addToList);
65
- uploadedFilesListReference.current = addToList(uploadedFilesListReference.current);
75
+ updateFileList(list => [...list, recentUploadedFile]);
66
76
  }
67
- const removeFileFromList = file => {
68
- function filterOutFrom(listToFilterFrom) {
69
- return listToFilterFrom.filter(fileInList => file !== fileInList && file.id !== fileInList.id);
70
- }
71
- setUploadedFiles(filterOutFrom);
72
- uploadedFilesListReference.current = filterOutFrom(uploadedFilesListReference.current);
73
- };
74
- const modifyFileInList = (file, updates) => {
75
- const updateListItem = listToUpdate => listToUpdate.map(fileInList => {
76
- return fileInList === file || fileInList.id === file.id ? {
77
- ...file,
78
- ...updates
79
- } : fileInList;
77
+ function removeFileFromList(file) {
78
+ updateFileList(list => list.filter(fileInList => file !== fileInList && file.id !== fileInList.id));
79
+ }
80
+ function modifyFileInList(file, updates) {
81
+ updateFileList(list => list.map(fileInList => fileInList === file || fileInList.id === file.id ? {
82
+ ...file,
83
+ ...updates
84
+ } : fileInList));
85
+ }
86
+ function focusNextItem(focusId = null, isLastItem = false, timeout = FOCUS_TIMEOUT) {
87
+ const nextFocusIdIndex = focusId ? uploadedFilesListReference.current.findIndex(item => item.id === focusId) : -1;
88
+ requestAnimationFrame(() => {
89
+ setTimeout(() => {
90
+ if (isLastItem || nextFocusIdIndex === -1) {
91
+ // If it's the last item or no next item, focus on the upload input reference
92
+ uploadInputRef.current?.focus();
93
+ } else {
94
+ const nextFocusElement = itemRefs.current[nextFocusIdIndex];
95
+ nextFocusElement?.focus();
96
+ }
97
+ }, timeout);
80
98
  });
81
- setUploadedFiles(updateListItem);
82
- uploadedFilesListReference.current = updateListItem(uploadedFilesListReference.current);
83
- };
84
- const [fileToRemove, setFileToRemove] = useState(null);
99
+ }
85
100
  const removeFile = file => {
86
101
  const {
87
102
  id,
88
103
  status
89
104
  } = file;
90
105
  const index = uploadedFiles.findIndex(f => f.id === file.id);
91
- setFileToRemoveIndex(index);
106
+ const isLastItem = index === uploadedFiles.length - 1;
107
+ const nextIndexId = uploadedFiles[index + 1]?.id;
108
+ const focusId = nextIndexId ?? null;
92
109
  if (status === Status.FAILED) {
93
110
  removeFileFromList(file);
94
- setFileToRemove(file);
111
+ setNextFocusItem({
112
+ focusId: focusId ?? null,
113
+ isLastItem
114
+ });
95
115
  } else if (onDeleteFile && id) {
96
116
  modifyFileInList(file, {
97
117
  status: Status.PROCESSING,
98
118
  error: undefined
99
119
  });
120
+ setNextFocusItem({
121
+ focusId,
122
+ isLastItem
123
+ });
100
124
  onDeleteFile(id).then(() => {
101
125
  removeFileFromList(file);
102
126
  }).catch(error => {
103
127
  modifyFileInList(file, {
104
128
  error: error
105
129
  });
106
- }).finally(() => {
107
- setFileToRemove(file);
130
+ setNextFocusItem({
131
+ focusId,
132
+ isLastItem
133
+ });
108
134
  });
109
135
  }
110
136
  };
@@ -136,22 +162,17 @@ const UploadInput = ({
136
162
  const numberOfValidFiles = getNumberOfFilesUploaded();
137
163
  return numberOfValidFiles >= maxFiles;
138
164
  }
139
- // One or more files selected, create entries for them
140
165
  const addFiles = selectedFiles => {
141
166
  for (let i = 0; i < selectedFiles.length; i += 1) {
142
167
  const file = selectedFiles.item(i);
143
- // Returning a FormData[] array instead of FileList so we can filter out incorrect files
144
168
  const formData = new FormData();
145
169
  if (file) {
146
170
  generateFileId(file);
147
171
  const allowedFileTypes = typeof fileTypes === 'string' ? fileTypes : fileTypes.join(',');
148
- // Check if file type is valid
149
172
  if (!isTypeValid(file, allowedFileTypes)) {
150
173
  handleFileUploadFailure(file, formatMessage(MESSAGES.fileTypeNotSupported));
151
174
  continue;
152
175
  }
153
- // Check if the filesize is valid
154
- // Convert to rough bytes
155
176
  if (!isSizeValid(file, sizeLimit * 1000)) {
156
177
  const failureMessage = sizeLimitErrorMessage || formatMessage(MESSAGES.fileIsTooLarge);
157
178
  handleFileUploadFailure(file, failureMessage);
@@ -164,13 +185,10 @@ const UploadInput = ({
164
185
  handleFileUploadFailure(file, failureMessage);
165
186
  continue;
166
187
  }
167
- // Check if the file is already in the list
168
188
  const existingFile = uploadedFiles.find(f => f.filename === file.name);
169
189
  if (existingFile) {
170
- // Remove the file from the list before adding it again
171
190
  removeFileFromList(existingFile);
172
191
  }
173
- // Add the file to the list
174
192
  formData.append(fileInputName, file);
175
193
  const pendingFile = {
176
194
  id: generateFileId(file),
@@ -178,13 +196,11 @@ const UploadInput = ({
178
196
  status: Status.PENDING
179
197
  };
180
198
  addFileToList(pendingFile);
181
- // Start uploading the file
182
199
  onUploadFile(formData).then(({
183
200
  id,
184
201
  url,
185
202
  error
186
203
  }) => {
187
- // Replace the temporary id with the final one received from the API, and also set any errors
188
204
  modifyFileInList(pendingFile, {
189
205
  id,
190
206
  url,
@@ -198,27 +214,17 @@ const UploadInput = ({
198
214
  });
199
215
  });
200
216
  if (!multiple) {
201
- // Only upload a single file
202
217
  break;
203
218
  }
204
219
  }
205
220
  }
206
221
  };
207
222
  useLayoutEffect(() => {
208
- if (fileToRemove && fileToRemoveIndex !== null) {
209
- requestAnimationFrame(() => {
210
- const nextFocusIndex = Math.min(fileToRemoveIndex, uploadedFiles.length - 1);
211
- if (itemRefs.current[nextFocusIndex]) {
212
- itemRefs.current[nextFocusIndex].focus(); // Focus the next UploadItem
213
- } else {
214
- // If there's only one item left, focus the UploadButton
215
- uploadInputRef.current?.focus();
216
- }
217
- });
218
- setFileToRemove(null); // Reset the state
219
- setFileToRemoveIndex(null); // Reset the index
223
+ if (nextFocusItem) {
224
+ focusNextItem(nextFocusItem.focusId, nextFocusItem.isLastItem);
220
225
  }
221
- }, [uploadedFiles, fileToRemove, fileToRemoveIndex, itemRefs, uploadInputRef]);
226
+ setNextFocusItem(null);
227
+ }, [nextFocusItem]);
222
228
  useEffect(() => {
223
229
  setMounted(true);
224
230
  }, []);