@transferwise/components 46.140.0 → 46.141.0

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.
Files changed (151) hide show
  1. package/build/avatarWrapper/AvatarWrapper.js +3 -4
  2. package/build/avatarWrapper/AvatarWrapper.js.map +1 -1
  3. package/build/avatarWrapper/AvatarWrapper.mjs +4 -5
  4. package/build/avatarWrapper/AvatarWrapper.mjs.map +1 -1
  5. package/build/button/LegacyButton.js.map +1 -1
  6. package/build/button/LegacyButton.mjs.map +1 -1
  7. package/build/common/hooks/useHasIntersected/useHasIntersected.js +6 -4
  8. package/build/common/hooks/useHasIntersected/useHasIntersected.js.map +1 -1
  9. package/build/common/hooks/useHasIntersected/useHasIntersected.mjs +6 -4
  10. package/build/common/hooks/useHasIntersected/useHasIntersected.mjs.map +1 -1
  11. package/build/common/liveRegion/LiveRegion.js +4 -1
  12. package/build/common/liveRegion/LiveRegion.js.map +1 -1
  13. package/build/common/liveRegion/LiveRegion.mjs +4 -1
  14. package/build/common/liveRegion/LiveRegion.mjs.map +1 -1
  15. package/build/dateInput/DateInput.js +10 -10
  16. package/build/dateInput/DateInput.js.map +1 -1
  17. package/build/dateInput/DateInput.mjs +10 -10
  18. package/build/dateInput/DateInput.mjs.map +1 -1
  19. package/build/dateLookup/DateLookup.js +1 -1
  20. package/build/dateLookup/DateLookup.js.map +1 -1
  21. package/build/dateLookup/DateLookup.mjs +1 -1
  22. package/build/dateLookup/DateLookup.mjs.map +1 -1
  23. package/build/dateLookup/monthCalendar/table/MonthCalendarTable.js +1 -1
  24. package/build/dateLookup/monthCalendar/table/MonthCalendarTable.js.map +1 -1
  25. package/build/dateLookup/monthCalendar/table/MonthCalendarTable.mjs +1 -1
  26. package/build/dateLookup/monthCalendar/table/MonthCalendarTable.mjs.map +1 -1
  27. package/build/dateLookup/yearCalendar/table/YearCalendarTable.js +1 -1
  28. package/build/dateLookup/yearCalendar/table/YearCalendarTable.js.map +1 -1
  29. package/build/dateLookup/yearCalendar/table/YearCalendarTable.mjs +1 -1
  30. package/build/dateLookup/yearCalendar/table/YearCalendarTable.mjs.map +1 -1
  31. package/build/expressiveMoneyInput/ExpressiveMoneyInput.js.map +1 -1
  32. package/build/expressiveMoneyInput/ExpressiveMoneyInput.mjs.map +1 -1
  33. package/build/expressiveMoneyInput/amountInput/AmountInput.js +17 -11
  34. package/build/expressiveMoneyInput/amountInput/AmountInput.js.map +1 -1
  35. package/build/expressiveMoneyInput/amountInput/AmountInput.mjs +18 -12
  36. package/build/expressiveMoneyInput/amountInput/AmountInput.mjs.map +1 -1
  37. package/build/expressiveMoneyInput/hooks/useInputStyle.js +8 -6
  38. package/build/expressiveMoneyInput/hooks/useInputStyle.js.map +1 -1
  39. package/build/expressiveMoneyInput/hooks/useInputStyle.mjs +9 -7
  40. package/build/expressiveMoneyInput/hooks/useInputStyle.mjs.map +1 -1
  41. package/build/header/Header.js +1 -1
  42. package/build/header/Header.js.map +1 -1
  43. package/build/header/Header.mjs +1 -1
  44. package/build/header/Header.mjs.map +1 -1
  45. package/build/inputs/SelectInput/BottomSheet/SelectInputBottomSheet.js.map +1 -1
  46. package/build/inputs/SelectInput/BottomSheet/SelectInputBottomSheet.mjs.map +1 -1
  47. package/build/inputs/SelectInput/Options/SelectInputOptions.js +34 -22
  48. package/build/inputs/SelectInput/Options/SelectInputOptions.js.map +1 -1
  49. package/build/inputs/SelectInput/Options/SelectInputOptions.mjs +35 -23
  50. package/build/inputs/SelectInput/Options/SelectInputOptions.mjs.map +1 -1
  51. package/build/inputs/SelectInput/Popover/SelectInputPopover.js.map +1 -1
  52. package/build/inputs/SelectInput/Popover/SelectInputPopover.mjs.map +1 -1
  53. package/build/inputs/SelectInput/SelectInput.js +8 -6
  54. package/build/inputs/SelectInput/SelectInput.js.map +1 -1
  55. package/build/inputs/SelectInput/SelectInput.mjs +9 -7
  56. package/build/inputs/SelectInput/SelectInput.mjs.map +1 -1
  57. package/build/inputs/SelectInput/TriggerButton/SelectInputTriggerButton.js.map +1 -1
  58. package/build/inputs/SelectInput/TriggerButton/SelectInputTriggerButton.mjs.map +1 -1
  59. package/build/main.css +58 -53
  60. package/build/nudge/Nudge.js +31 -15
  61. package/build/nudge/Nudge.js.map +1 -1
  62. package/build/nudge/Nudge.mjs +32 -16
  63. package/build/nudge/Nudge.mjs.map +1 -1
  64. package/build/phoneNumberInput/PhoneNumberInput.js +9 -12
  65. package/build/phoneNumberInput/PhoneNumberInput.js.map +1 -1
  66. package/build/phoneNumberInput/PhoneNumberInput.mjs +9 -12
  67. package/build/phoneNumberInput/PhoneNumberInput.mjs.map +1 -1
  68. package/build/promoCard/PromoCardGroup.js +34 -16
  69. package/build/promoCard/PromoCardGroup.js.map +1 -1
  70. package/build/promoCard/PromoCardGroup.mjs +35 -17
  71. package/build/promoCard/PromoCardGroup.mjs.map +1 -1
  72. package/build/segmentedControl/SegmentedControl.js +6 -1
  73. package/build/segmentedControl/SegmentedControl.js.map +1 -1
  74. package/build/segmentedControl/SegmentedControl.mjs +7 -2
  75. package/build/segmentedControl/SegmentedControl.mjs.map +1 -1
  76. package/build/styles/css/neptune.css +58 -53
  77. package/build/styles/less/neptune-tokens.less +2 -2
  78. package/build/styles/main.css +58 -53
  79. package/build/styles/props/neptune-tokens.css +1 -1
  80. package/build/styles/styles/less/core/viewport-themes.css +46 -42
  81. package/build/styles/styles/less/neptune.css +58 -53
  82. package/build/tabs/Tabs.js +1 -1
  83. package/build/tabs/Tabs.js.map +1 -1
  84. package/build/tabs/Tabs.mjs +1 -1
  85. package/build/tabs/Tabs.mjs.map +1 -1
  86. package/build/tooltip/Tooltip.js +6 -3
  87. package/build/tooltip/Tooltip.js.map +1 -1
  88. package/build/tooltip/Tooltip.mjs +6 -3
  89. package/build/tooltip/Tooltip.mjs.map +1 -1
  90. package/build/types/avatarWrapper/AvatarWrapper.d.ts.map +1 -1
  91. package/build/types/common/hooks/useHasIntersected/useHasIntersected.d.ts.map +1 -1
  92. package/build/types/common/liveRegion/LiveRegion.d.ts.map +1 -1
  93. package/build/types/dateLookup/monthCalendar/table/MonthCalendarTable.d.ts.map +1 -1
  94. package/build/types/expressiveMoneyInput/ExpressiveMoneyInput.d.ts.map +1 -1
  95. package/build/types/expressiveMoneyInput/amountInput/AmountInput.d.ts.map +1 -1
  96. package/build/types/expressiveMoneyInput/hooks/useInputStyle.d.ts +2 -2
  97. package/build/types/expressiveMoneyInput/hooks/useInputStyle.d.ts.map +1 -1
  98. package/build/types/expressiveMoneyInput/hooks/useSelectionRange.d.ts.map +1 -1
  99. package/build/types/inputs/SelectInput/BottomSheet/SelectInputBottomSheet.d.ts.map +1 -1
  100. package/build/types/inputs/SelectInput/Options/SelectInputOptions.d.ts.map +1 -1
  101. package/build/types/inputs/SelectInput/Popover/SelectInputPopover.d.ts.map +1 -1
  102. package/build/types/inputs/SelectInput/SelectInput.d.ts.map +1 -1
  103. package/build/types/nudge/Nudge.d.ts.map +1 -1
  104. package/build/types/phoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
  105. package/build/types/promoCard/PromoCardGroup.d.ts.map +1 -1
  106. package/build/types/segmentedControl/SegmentedControl.d.ts.map +1 -1
  107. package/build/types/tooltip/Tooltip.d.ts.map +1 -1
  108. package/build/types/uploadInput/UploadInput.d.ts.map +1 -1
  109. package/build/uploadInput/UploadInput.js +29 -25
  110. package/build/uploadInput/UploadInput.js.map +1 -1
  111. package/build/uploadInput/UploadInput.mjs +29 -25
  112. package/build/uploadInput/UploadInput.mjs.map +1 -1
  113. package/package.json +3 -3
  114. package/src/avatarWrapper/AvatarWrapper.test.tsx +33 -3
  115. package/src/avatarWrapper/AvatarWrapper.tsx +5 -6
  116. package/src/button/LegacyButton.tsx +1 -1
  117. package/src/button/_stories/Button.test.story.tsx +3 -3
  118. package/src/common/hooks/useContainerSize.test.tsx +1 -1
  119. package/src/common/hooks/useHasIntersected/useHasIntersected.ts +12 -4
  120. package/src/common/liveRegion/LiveRegion.tsx +5 -2
  121. package/src/dateInput/DateInput.tsx +10 -10
  122. package/src/dateLookup/DateLookup.test.story.tsx +16 -0
  123. package/src/dateLookup/DateLookup.tsx +1 -1
  124. package/src/dateLookup/monthCalendar/table/MonthCalendarTable.tsx +1 -5
  125. package/src/dateLookup/yearCalendar/table/YearCalendarTable.tsx +1 -1
  126. package/src/expressiveMoneyInput/ExpressiveMoneyInput.tsx +1 -1
  127. package/src/expressiveMoneyInput/amountInput/AmountInput.tsx +22 -15
  128. package/src/expressiveMoneyInput/hooks/useInputStyle.ts +20 -8
  129. package/src/expressiveMoneyInput/hooks/useSelectionRange.ts +2 -0
  130. package/src/header/Header.tsx +2 -2
  131. package/src/inputs/SelectInput/BottomSheet/SelectInputBottomSheet.tsx +4 -0
  132. package/src/inputs/SelectInput/Options/SelectInputOptions.tsx +43 -27
  133. package/src/inputs/SelectInput/Popover/SelectInputPopover.tsx +4 -0
  134. package/src/inputs/SelectInput/SelectInput.tsx +21 -15
  135. package/src/inputs/SelectInput/TriggerButton/SelectInputTriggerButton.tsx +1 -1
  136. package/src/main.css +58 -53
  137. package/src/nudge/Nudge.tsx +29 -20
  138. package/src/phoneNumberInput/PhoneNumberInput.test.tsx +16 -0
  139. package/src/phoneNumberInput/PhoneNumberInput.tsx +11 -13
  140. package/src/promoCard/PromoCard.story.tsx +3 -3
  141. package/src/promoCard/PromoCardGroup.tsx +39 -21
  142. package/src/segmentedControl/SegmentedControl.test.tsx +25 -0
  143. package/src/segmentedControl/SegmentedControl.tsx +7 -1
  144. package/src/select/Select.story.tsx +1 -1
  145. package/src/styles/less/core/viewport-themes.css +46 -42
  146. package/src/styles/less/core/viewport-themes.less +2 -45
  147. package/src/styles/less/neptune.css +58 -53
  148. package/src/tabs/Tabs.tsx +1 -1
  149. package/src/tooltip/Tooltip.tsx +3 -0
  150. package/src/uploadInput/UploadInput.test.tsx +19 -0
  151. package/src/uploadInput/UploadInput.tsx +28 -24
@@ -77,12 +77,12 @@ const UploadInput = ({
77
77
  });
78
78
  const [markedFileForDelete, setMarkedFileForDelete] = useState(null);
79
79
  const [lastAttemptedDeleteId, setLastAttemptedDeleteId] = useState(null);
80
- const [mounted, setMounted] = useState(false);
80
+ const mountedRef = useRef(false);
81
81
  const {
82
82
  formatMessage
83
83
  } = useIntl();
84
84
  const uploadInputRef = useRef(null);
85
- let fileRefs = [];
85
+ const fileRefs = useRef([]);
86
86
  const PROGRESS_STATUSES = new Set([Status.PENDING, Status.PROCESSING]);
87
87
  const [uploadedFiles, setUploadedFiles] = useState(multiple || files.length === 0 ? files : [files[0]]);
88
88
  const uploadedFilesListReference = useRef(multiple || files.length === 0 ? files : [files[0]]);
@@ -95,7 +95,7 @@ const UploadInput = ({
95
95
  }
96
96
  function removeFileFromList(file) {
97
97
  updateFileList(list => list.filter(fileInList => file !== fileInList && file.id !== fileInList.id));
98
- fileRefs = fileRefs.filter(ref => ref && ref.id !== file.id);
98
+ fileRefs.current = fileRefs.current.filter(ref => ref && ref.id !== file.id);
99
99
  }
100
100
  function modifyFileInList(file, updates) {
101
101
  updateFileList(list => list.map(fileInList => fileInList === file || fileInList.id === file.id ? {
@@ -105,20 +105,20 @@ const UploadInput = ({
105
105
  }
106
106
  const removeFile = async file => {
107
107
  const {
108
- id,
108
+ id: fileId,
109
109
  status
110
110
  } = file;
111
- fileRefs = fileRefs.filter(item => item && item.id !== file.id);
111
+ fileRefs.current = fileRefs.current.filter(item => item && item.id !== file.id);
112
112
  if (status === Status.FAILED) {
113
113
  removeFileFromList(file);
114
114
  return Promise.resolve();
115
115
  }
116
- if (onDeleteFile && id) {
116
+ if (onDeleteFile && fileId) {
117
117
  modifyFileInList(file, {
118
118
  status: Status.PROCESSING,
119
119
  error: undefined
120
120
  });
121
- return onDeleteFile(id).then(() => {
121
+ return onDeleteFile(fileId).then(() => {
122
122
  removeFileFromList(file);
123
123
  }).catch(error => {
124
124
  modifyFileInList(file, {
@@ -211,19 +211,21 @@ const UploadInput = ({
211
211
  }
212
212
  };
213
213
  useEffect(() => {
214
- setMounted(true);
215
- }, []);
216
- useEffect(() => {
217
- if (onFilesChange && mounted) {
214
+ // Skip onFilesChange call on initial mount, only call on updates
215
+ if (!mountedRef.current) {
216
+ mountedRef.current = true;
217
+ return;
218
+ }
219
+ if (onFilesChange) {
218
220
  onFilesChange([...uploadedFiles]);
219
221
  }
220
- }, [onFilesChange, uploadedFiles]); // eslint-disable-line react-hooks/exhaustive-deps
221
- const [nextFocusable, setNextFocusable] = useState(uploadInputRef.current);
222
+ }, [onFilesChange, uploadedFiles]);
223
+ const [nextFocusable, setNextFocusable] = useState(null);
222
224
  const handleFocus = fileId => {
223
- fileRefs = fileRefs.filter(ref => {
225
+ fileRefs.current = fileRefs.current.filter(ref => {
224
226
  return ref && ref.id !== markedFileForDelete?.id;
225
227
  });
226
- const filesCount = fileRefs.length;
228
+ const filesCount = fileRefs.current.length;
227
229
  let next = uploadInputRef.current;
228
230
  let focusTarget = 'button';
229
231
  // If there will be no files left after deletion, focus the upload button
@@ -233,14 +235,14 @@ const UploadInput = ({
233
235
  return;
234
236
  }
235
237
  if (filesCount > 1) {
236
- const currentFileIndex = fileRefs.findIndex(file => file?.id === fileId);
237
- const currentFileId = fileRefs?.[currentFileIndex]?.id;
238
- const lastFileId = fileRefs?.[filesCount - 1]?.id;
238
+ const currentFileIndex = fileRefs.current.findIndex(file => file?.id === fileId);
239
+ const currentFileId = fileRefs.current?.[currentFileIndex]?.id;
240
+ const lastFileId = fileRefs.current?.[filesCount - 1]?.id;
239
241
  // if last file, select a previous one
240
242
  if (currentFileId === lastFileId) {
241
- next = fileRefs[filesCount - 2];
243
+ next = fileRefs.current[filesCount - 2];
242
244
  } else {
243
- next = fileRefs[currentFileIndex + 1];
245
+ next = fileRefs.current[currentFileIndex + 1];
244
246
  }
245
247
  // If next is an UploadItemRef, check if it has a URL (succeeded)
246
248
  if (next && 'status' in next) {
@@ -271,7 +273,7 @@ const UploadInput = ({
271
273
  // If there are no files left, focus the upload button
272
274
  if (uploadedFiles.length === 0 && uploadInputRef.current && typeof uploadInputRef.current.focus === 'function') {
273
275
  setTimeout(() => {
274
- uploadInputRef.current.focus();
276
+ uploadInputRef.current?.focus();
275
277
  }, 0);
276
278
  } else if (typeof focusTarget === 'object' && 'ref' in focusTarget && focusTarget.ref && typeof focusTarget.ref.focus === 'function') {
277
279
  setTimeout(() => {
@@ -299,10 +301,10 @@ const UploadInput = ({
299
301
  "aria-live": "polite",
300
302
  "aria-relevant": "all",
301
303
  role: "region",
302
- children: uploadedFiles.map((file, index) => /*#__PURE__*/jsx(UploadItem, {
304
+ children: uploadedFiles.map(file => /*#__PURE__*/jsx(UploadItem, {
303
305
  ref: el => {
304
- if (el && el.id !== markedFileForDelete?.id && !fileRefs.some(ref => ref && ref.id === el.id) && el.status !== 'processing') {
305
- fileRefs.push(el);
306
+ if (el && el.id !== markedFileForDelete?.id && !fileRefs.current.some(ref => ref?.id === el.id) && el.status !== 'processing') {
307
+ fileRefs.current.push(el);
306
308
  }
307
309
  },
308
310
  file: file,
@@ -324,7 +326,9 @@ const UploadInput = ({
324
326
  children: /*#__PURE__*/jsx(UploadButton, {
325
327
  ref: uploadInputRef,
326
328
  id: id,
327
- uploadButtonTitle: uploadButtonTitle,
329
+ uploadButtonTitle: uploadButtonTitle
330
+ // eslint-disable-next-line react-hooks/refs -- Function reads ref for file count check
331
+ ,
328
332
  disabled: areMaximumFilesUploadedAlready() || disabled,
329
333
  multiple: multiple,
330
334
  fileTypes: fileTypes,
@@ -1 +1 @@
1
- {"version":3,"file":"UploadInput.mjs","sources":["../../src/uploadInput/UploadInput.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport { useEffect, 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 * @default []\n */\n files?: readonly UploadedFile[];\n\n /**\n * The key of the file in the returned FormData object (default: file)\n * @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 allowed size limit are uploaded\n */\n sizeLimitErrorMessage?: string;\n} & {\n /** @default false */\n multiple?: UploadButtonProps['multiple'];\n /** @default ['.pdf,application/pdf', '.jpg,.jpeg,image/jpeg', '.png,image/png'] */\n fileTypes?: UploadButtonProps['fileTypes'];\n /** @default 5000 */\n sizeLimit?: UploadButtonProps['sizeLimit'];\n} & Pick<UploadButtonProps, 'disabled' | 'description' | 'id' | 'uploadButtonTitle'> & {\n onDownload?: UploadItemProps['onDownload'];\n } & 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 * Required id of the UploadItem component.\n */\n id: string | number;\n\n /**\n * Optional status of the UploadItem component.\n */\n status?: string;\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 [lastAttemptedDeleteId, setLastAttemptedDeleteId] = useState<string | number | null>(null);\n const [mounted, setMounted] = useState(false);\n const { formatMessage } = useIntl();\n const uploadInputRef = useRef<HTMLInputElement | null>(null);\n let fileRefs: (HTMLDivElement | UploadItemRef | 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 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 fileRefs = fileRefs.filter((ref) => ref && ref.id !== file.id);\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 const removeFile = async (file: UploadedFile) => {\n const { id, status } = file;\n fileRefs = fileRefs.filter((item) => item && item.id !== file.id);\n\n if (status === Status.FAILED) {\n removeFileFromList(file);\n return Promise.resolve();\n }\n\n if (onDeleteFile && id) {\n modifyFileInList(file, { status: Status.PROCESSING, error: undefined });\n\n return onDeleteFile(id)\n .then(() => {\n removeFileFromList(file);\n })\n .catch((error) => {\n modifyFileInList(file, { error: error as UploadError });\n });\n }\n };\n\n function handleFileUploadFailure(file: File, failureMessage: string) {\n const { name } = file;\n\n const failedUpload = {\n id: generateFileId(file),\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 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 (typeof sizeLimit === 'number' && !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 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 type NextFocusable =\n | HTMLDivElement\n | UploadItemRef\n | { ref: HTMLDivElement | UploadItemRef; target: 'button' | 'link' }\n | null;\n\n const [nextFocusable, setNextFocusable] = useState<NextFocusable>(uploadInputRef.current);\n\n const handleFocus = (fileId: string | number) => {\n fileRefs = fileRefs.filter((ref) => {\n return ref && ref.id !== markedFileForDelete?.id;\n });\n\n const filesCount = fileRefs.length;\n let next: UploadItemRef | HTMLDivElement | null = uploadInputRef.current;\n let focusTarget: 'button' | 'link' = 'button';\n\n // If there will be no files left after deletion, focus the upload button\n if (filesCount === 1) {\n next = uploadInputRef.current;\n setNextFocusable(next);\n return;\n }\n\n if (filesCount > 1) {\n const currentFileIndex = fileRefs.findIndex((file) => file?.id === fileId);\n const currentFileId = fileRefs?.[currentFileIndex]?.id;\n const lastFileId = fileRefs?.[filesCount - 1]?.id;\n\n // if last file, select a previous one\n if (currentFileId === lastFileId) {\n next = fileRefs[filesCount - 2];\n } else {\n next = fileRefs[currentFileIndex + 1];\n }\n\n // If next is an UploadItemRef, check if it has a URL (succeeded)\n if (next && 'status' in next) {\n // Find the file object for this ref\n const fileObj = uploadedFiles.find((f) => f.id === next?.id);\n if (\n fileObj &&\n (fileObj.status === Status.SUCCEEDED || fileObj.status === Status.DONE) &&\n fileObj.url\n ) {\n focusTarget = 'link';\n }\n }\n setNextFocusable(() => {\n if (next && typeof (next as UploadItemRef).focus === 'function') {\n return { ref: next, target: focusTarget };\n }\n return next;\n });\n }\n };\n\n const handleRefocus = () => {\n const focusTarget = nextFocusable;\n if (lastAttemptedDeleteId) {\n setLastAttemptedDeleteId(null);\n return;\n }\n if (focusTarget) {\n // If there are no files left, focus the upload button\n if (\n uploadedFiles.length === 0 &&\n uploadInputRef.current &&\n typeof uploadInputRef.current.focus === 'function'\n ) {\n setTimeout(() => {\n uploadInputRef.current!.focus();\n }, 0);\n } else if (\n typeof focusTarget === 'object' &&\n 'ref' in focusTarget &&\n focusTarget.ref &&\n typeof focusTarget.ref.focus === 'function'\n ) {\n setTimeout(() => {\n if (focusTarget.ref && typeof (focusTarget.ref as UploadItemRef).focus === 'function') {\n // @ts-expect-error: focus may not exist on all possible ref types, but is safe here\n (focusTarget.ref as UploadItemRef).focus(focusTarget.target);\n }\n }, 0);\n } else if (focusTarget && typeof (focusTarget as UploadItemRef).focus === 'function') {\n setTimeout(() => {\n (focusTarget as UploadItemRef).focus();\n }, 0);\n }\n }\n };\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 if (\n el &&\n el.id !== markedFileForDelete?.id &&\n !fileRefs.some((ref) => ref && ref.id === el.id) &&\n el.status !== 'processing'\n ) {\n fileRefs.push(el);\n }\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 ? async () => {\n setLastAttemptedDeleteId(file.id);\n await removeFile(file);\n handleRefocus();\n }\n : () => {\n setLastAttemptedDeleteId(file.id);\n setMarkedFileForDelete(file);\n }\n }\n onDownload={onDownload}\n onFocus={() => handleFocus(file.id)}\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 tabIndex={markedFileForDelete ? 0 : -1}\n onClick={() => {\n if (markedFileForDelete) {\n void removeFile(markedFileForDelete);\n }\n setMarkedFileForDelete(null);\n setLastAttemptedDeleteId(null);\n }}\n >\n {deleteConfirm?.confirmText || formatMessage(MESSAGES.deleteModalConfirmButtonText)}\n </Button>\n </>\n }\n onUnmount={handleRefocus}\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","lastAttemptedDeleteId","setLastAttemptedDeleteId","mounted","setMounted","formatMessage","useIntl","uploadInputRef","useRef","fileRefs","PROGRESS_STATUSES","Set","Status","PENDING","PROCESSING","uploadedFiles","setUploadedFiles","length","uploadedFilesListReference","updateFileList","updateFn","current","addFileToList","recentUploadedFile","list","removeFileFromList","filter","fileInList","ref","modifyFileInList","updates","map","removeFile","status","item","FAILED","Promise","resolve","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","f","append","pendingFile","url","useEffect","nextFocusable","setNextFocusable","handleFocus","fileId","filesCount","next","focusTarget","currentFileIndex","findIndex","currentFileId","lastFileId","fileObj","DONE","focus","target","handleRefocus","setTimeout","_jsxs","_Fragment","children","role","clsx","_jsx","index","UploadItem","el","some","push","singleFileUpload","canDelete","onDelete","onFocus","UploadButton","withEntries","Boolean","onChange","Modal","title","deleteModalTitle","body","deleteModalBody","open","footer","Button","block","onClick","cancelText","deleteModalCancelButtonText","priority","Priority","SECONDARY","type","ControlType","NEGATIVE","tabIndex","confirmText","deleteModalConfirmButtonText","onUnmount","onClose"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqIA,SAASA,cAAcA,CAACC,IAAU,EAAA;EAChC,MAAM;IAAEC,IAAI;AAAEC,IAAAA;AAAI,GAAE,GAAGF,IAAI;EAC3B,MAAMG,eAAe,GAAG,IAAIC,IAAI,EAAE,CAACC,OAAO,EAAE;AAC5C,EAAA,OAAO,GAAGJ,IAAI,CAAA,CAAA,EAAIC,IAAI,CAAA,CAAA,EAAIC,eAAe,CAAA,CAAE;AAC7C;AAEA;;;;;;;;AAQG;AACH,MAAMG,WAAW,GAAGA,CAAC;AACnBC,EAAAA,KAAK,GAAG,EAAE;AACVC,EAAAA,aAAa,GAAG,MAAM;EACtBC,SAAS;EACTC,aAAa;EACbC,QAAQ;AACRC,EAAAA,QAAQ,GAAG,KAAK;AAChBC,EAAAA,SAAS,GAAGC,cAAc;AAC1BC,EAAAA,SAAS,GAAGC,kBAAkB;EAC9BC,WAAW;EACXC,YAAY;EACZC,YAAY;EACZC,iBAAiB;EACjBC,aAAa;EACbC,UAAU;EACVC,QAAQ;EACRC,oBAAoB;EACpBC,EAAE;EACFC,qBAAqB;AACrBC,EAAAA;AAAiB,CACA,KAAI;EACrB,MAAMC,eAAe,GAAGC,kBAAkB,CAAC;AAAEC,IAAAA,YAAY,EAAE;AAAI,GAAE,CAAC;EAClE,MAAM,CAACC,mBAAmB,EAAEC,sBAAsB,CAAC,GAAGC,QAAQ,CAAsB,IAAI,CAAC;EACzF,MAAM,CAACC,qBAAqB,EAAEC,wBAAwB,CAAC,GAAGF,QAAQ,CAAyB,IAAI,CAAC;EAChG,MAAM,CAACG,OAAO,EAAEC,UAAU,CAAC,GAAGJ,QAAQ,CAAC,KAAK,CAAC;EAC7C,MAAM;AAAEK,IAAAA;GAAe,GAAGC,OAAO,EAAE;AACnC,EAAA,MAAMC,cAAc,GAAGC,MAAM,CAA0B,IAAI,CAAC;EAC5D,IAAIC,QAAQ,GAA8C,EAAE;AAE5D,EAAA,MAAMC,iBAAiB,GAAG,IAAIC,GAAG,CAAC,CAACC,MAAM,CAACC,OAAO,EAAED,MAAM,CAACE,UAAU,CAAC,CAAC;EAEtE,MAAM,CAACC,aAAa,EAAEC,gBAAgB,CAAC,GAAGhB,QAAQ,CAChDrB,QAAQ,IAAIL,KAAK,CAAC2C,MAAM,KAAK,CAAC,GAAG3C,KAAK,GAAG,CAACA,KAAK,CAAC,CAAC,CAAC,CAAC,CACpD;EAED,MAAM4C,0BAA0B,GAAGV,MAAM,CAAC7B,QAAQ,IAAIL,KAAK,CAAC2C,MAAM,KAAK,CAAC,GAAG3C,KAAK,GAAG,CAACA,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;EAE9F,SAAS6C,cAAcA,CAACC,QAAoE,EAAA;IAC1FJ,gBAAgB,CAACI,QAAQ,CAAC;IAC1BF,0BAA0B,CAACG,OAAO,GAAGD,QAAQ,CAACF,0BAA0B,CAACG,OAAO,CAAC;AACnF,EAAA;EAEA,SAASC,aAAaA,CAACC,kBAAgC,EAAA;IACrDJ,cAAc,CAAEK,IAAI,IAAK,CAAC,GAAGA,IAAI,EAAED,kBAAkB,CAAC,CAAC;AACzD,EAAA;EAEA,SAASE,kBAAkBA,CAAC1D,IAAkB,EAAA;IAC5CoD,cAAc,CAAEK,IAAI,IAClBA,IAAI,CAACE,MAAM,CAAEC,UAAU,IAAK5D,IAAI,KAAK4D,UAAU,IAAI5D,IAAI,CAACyB,EAAE,KAAKmC,UAAU,CAACnC,EAAE,CAAC,CAC9E;AACDiB,IAAAA,QAAQ,GAAGA,QAAQ,CAACiB,MAAM,CAAEE,GAAG,IAAKA,GAAG,IAAIA,GAAG,CAACpC,EAAE,KAAKzB,IAAI,CAACyB,EAAE,CAAC;AAChE,EAAA;AAEA,EAAA,SAASqC,gBAAgBA,CAAC9D,IAAkB,EAAE+D,OAA8B,EAAA;IAC1EX,cAAc,CAAEK,IAAI,IAClBA,IAAI,CAACO,GAAG,CAAEJ,UAAU,IAClBA,UAAU,KAAK5D,IAAI,IAAI4D,UAAU,CAACnC,EAAE,KAAKzB,IAAI,CAACyB,EAAE,GAAG;AAAE,MAAA,GAAGzB,IAAI;MAAE,GAAG+D;KAAS,GAAGH,UAAU,CACxF,CACF;AACH,EAAA;AAEA,EAAA,MAAMK,UAAU,GAAG,MAAOjE,IAAkB,IAAI;IAC9C,MAAM;MAAEyB,EAAE;AAAEyC,MAAAA;AAAM,KAAE,GAAGlE,IAAI;AAC3B0C,IAAAA,QAAQ,GAAGA,QAAQ,CAACiB,MAAM,CAAEQ,IAAI,IAAKA,IAAI,IAAIA,IAAI,CAAC1C,EAAE,KAAKzB,IAAI,CAACyB,EAAE,CAAC;AAEjE,IAAA,IAAIyC,MAAM,KAAKrB,MAAM,CAACuB,MAAM,EAAE;MAC5BV,kBAAkB,CAAC1D,IAAI,CAAC;AACxB,MAAA,OAAOqE,OAAO,CAACC,OAAO,EAAE;AAC1B,IAAA;IAEA,IAAInD,YAAY,IAAIM,EAAE,EAAE;MACtBqC,gBAAgB,CAAC9D,IAAI,EAAE;QAAEkE,MAAM,EAAErB,MAAM,CAACE,UAAU;AAAEwB,QAAAA,KAAK,EAAEC;AAAS,OAAE,CAAC;AAEvE,MAAA,OAAOrD,YAAY,CAACM,EAAE,CAAC,CACpBgD,IAAI,CAAC,MAAK;QACTf,kBAAkB,CAAC1D,IAAI,CAAC;AAC1B,MAAA,CAAC,CAAC,CACD0E,KAAK,CAAEH,KAAK,IAAI;QACfT,gBAAgB,CAAC9D,IAAI,EAAE;AAAEuE,UAAAA,KAAK,EAAEA;AAAoB,SAAE,CAAC;AACzD,MAAA,CAAC,CAAC;AACN,IAAA;EACF,CAAC;AAED,EAAA,SAASI,uBAAuBA,CAAC3E,IAAU,EAAE4E,cAAsB,EAAA;IACjE,MAAM;AAAE3E,MAAAA;AAAI,KAAE,GAAGD,IAAI;AAErB,IAAA,MAAM6E,YAAY,GAAG;AACnBpD,MAAAA,EAAE,EAAE1B,cAAc,CAACC,IAAI,CAAC;AACxB8E,MAAAA,QAAQ,EAAE7E,IAAI;MACdiE,MAAM,EAAErB,MAAM,CAACuB,MAAM;AACrBG,MAAAA,KAAK,EAAEK;KACR;IAEDrB,aAAa,CAACsB,YAAY,CAAC;AAE3B,IAAA,IAAIzD,iBAAiB,EAAE;MACrBA,iBAAiB,CAACyD,YAAY,CAAC;AACjC,IAAA;AACF,EAAA;EAEA,SAASE,wBAAwBA,GAAA;AAC/B,IAAA,MAAMC,qBAAqB,GAAG,IAAIpC,GAAG,CAAC,CAACC,MAAM,CAACoC,SAAS,EAAEpC,MAAM,CAACC,OAAO,CAAC,CAAC;IACzE,MAAMoC,UAAU,GAAG/B,0BAA0B,CAACG,OAAO,CAACK,MAAM,CACzD3D,IAAI,IAAKA,IAAI,CAACkE,MAAM,IAAIc,qBAAqB,CAACG,GAAG,CAACnF,IAAI,CAACkE,MAAM,CAAC,CAChE;IACD,OAAOgB,UAAU,CAAChC,MAAM;AAC1B,EAAA;EAEA,SAASkC,8BAA8BA,GAAA;IACrC,IAAI,CAAC7D,QAAQ,EAAE;AACb,MAAA,OAAO,KAAK;AACd,IAAA;AAEA,IAAA,MAAM8D,kBAAkB,GAAGN,wBAAwB,EAAE;IACrD,OAAOM,kBAAkB,IAAI9D,QAAQ;AACvC,EAAA;EAEA,MAAM+D,QAAQ,GAAIC,aAAuB,IAAI;AAC3C,IAAA,KAAK,IAAIC,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGD,aAAa,CAACrC,MAAM,EAAEsC,CAAC,IAAI,CAAC,EAAE;AAChD,MAAA,MAAMxF,IAAI,GAAGuF,aAAa,CAACpB,IAAI,CAACqB,CAAC,CAAC;AAElC,MAAA,MAAMC,QAAQ,GAAG,IAAIC,QAAQ,EAAE;AAE/B,MAAA,IAAI1F,IAAI,EAAE;AACR,QAAA,MAAM2F,gBAAgB,GAAG,OAAO9E,SAAS,KAAK,QAAQ,GAAGA,SAAS,GAAGA,SAAS,CAAC+E,IAAI,CAAC,GAAG,CAAC;AAExF,QAAA,IAAI,CAACC,WAAW,CAAC7F,IAAI,EAAE2F,gBAAgB,CAAC,EAAE;UACxChB,uBAAuB,CAAC3E,IAAI,EAAEsC,aAAa,CAACwD,QAAQ,CAACC,oBAAoB,CAAC,CAAC;AAC3E,UAAA;AACF,QAAA;AAEA,QAAA,IAAI,OAAOhF,SAAS,KAAK,QAAQ,IAAI,CAACiF,WAAW,CAAChG,IAAI,EAAEe,SAAS,GAAG,IAAI,CAAC,EAAE;UACzE,MAAM6D,cAAc,GAAGlD,qBAAqB,IAAIY,aAAa,CAACwD,QAAQ,CAACG,cAAc,CAAC;AACtFtB,UAAAA,uBAAuB,CAAC3E,IAAI,EAAE4E,cAAc,CAAC;AAC7C,UAAA;AACF,QAAA;QAEA,IAAIQ,8BAA8B,EAAE,EAAE;UACpC,MAAMR,cAAc,GAClBpD,oBAAoB,IACpBc,aAAa,CAACwD,QAAQ,CAACI,2BAA2B,EAAE;AAAEC,YAAAA,eAAe,EAAE5E;AAAQ,WAAE,CAAC;AACpFoD,UAAAA,uBAAuB,CAAC3E,IAAI,EAAE4E,cAAc,CAAC;AAC7C,UAAA;AACF,QAAA;AAEA,QAAA,MAAMwB,YAAY,GAAGpD,aAAa,CAACqD,IAAI,CAAEC,CAAC,IAAKA,CAAC,CAACxB,QAAQ,KAAK9E,IAAI,CAACC,IAAI,CAAC;AACxE,QAAA,IAAImG,YAAY,EAAE;UAChB1C,kBAAkB,CAAC0C,YAAY,CAAC;AAClC,QAAA;AAEAX,QAAAA,QAAQ,CAACc,MAAM,CAAC/F,aAAa,EAAER,IAAI,CAAC;AACpC,QAAA,MAAMwG,WAAW,GAAG;AAClB/E,UAAAA,EAAE,EAAE1B,cAAc,CAACC,IAAI,CAAC;UACxB8E,QAAQ,EAAE9E,IAAI,CAACC,IAAI;UACnBiE,MAAM,EAAErB,MAAM,CAACC;SAChB;QAEDS,aAAa,CAACiD,WAAW,CAAC;AAE1BtF,QAAAA,YAAY,CAACuE,QAAQ,CAAC,CACnBhB,IAAI,CAAC,CAAC;UAAEhD,EAAE;UAAEgF,GAAG;AAAElC,UAAAA;AAAK,SAAkB,KAAI;UAC3CT,gBAAgB,CAAC0C,WAAW,EAAE;YAAE/E,EAAE;YAAEgF,GAAG;YAAElC,KAAK;YAAEL,MAAM,EAAErB,MAAM,CAACoC;AAAS,WAAE,CAAC;AAC7E,QAAA,CAAC,CAAC,CACDP,KAAK,CAAEH,KAAK,IAAI;UACfT,gBAAgB,CAAC0C,WAAW,EAAE;AAAEjC,YAAAA,KAAK,EAAEA,KAAoB;YAAEL,MAAM,EAAErB,MAAM,CAACuB;AAAM,WAAE,CAAC;AACvF,QAAA,CAAC,CAAC;QAEJ,IAAI,CAACxD,QAAQ,EAAE;AACb,UAAA;AACF,QAAA;AACF,MAAA;AACF,IAAA;EACF,CAAC;AAED8F,EAAAA,SAAS,CAAC,MAAK;IACbrE,UAAU,CAAC,IAAI,CAAC;EAClB,CAAC,EAAE,EAAE,CAAC;AAENqE,EAAAA,SAAS,CAAC,MAAK;IACb,IAAIrF,aAAa,IAAIe,OAAO,EAAE;AAC5Bf,MAAAA,aAAa,CAAC,CAAC,GAAG2B,aAAa,CAAC,CAAC;AACnC,IAAA;EACF,CAAC,EAAE,CAAC3B,aAAa,EAAE2B,aAAa,CAAC,CAAC,CAAC;EAQnC,MAAM,CAAC2D,aAAa,EAAEC,gBAAgB,CAAC,GAAG3E,QAAQ,CAAgBO,cAAc,CAACc,OAAO,CAAC;EAEzF,MAAMuD,WAAW,GAAIC,MAAuB,IAAI;AAC9CpE,IAAAA,QAAQ,GAAGA,QAAQ,CAACiB,MAAM,CAAEE,GAAG,IAAI;MACjC,OAAOA,GAAG,IAAIA,GAAG,CAACpC,EAAE,KAAKM,mBAAmB,EAAEN,EAAE;AAClD,IAAA,CAAC,CAAC;AAEF,IAAA,MAAMsF,UAAU,GAAGrE,QAAQ,CAACQ,MAAM;AAClC,IAAA,IAAI8D,IAAI,GAA0CxE,cAAc,CAACc,OAAO;IACxE,IAAI2D,WAAW,GAAsB,QAAQ;AAE7C;IACA,IAAIF,UAAU,KAAK,CAAC,EAAE;MACpBC,IAAI,GAAGxE,cAAc,CAACc,OAAO;MAC7BsD,gBAAgB,CAACI,IAAI,CAAC;AACtB,MAAA;AACF,IAAA;IAEA,IAAID,UAAU,GAAG,CAAC,EAAE;AAClB,MAAA,MAAMG,gBAAgB,GAAGxE,QAAQ,CAACyE,SAAS,CAAEnH,IAAI,IAAKA,IAAI,EAAEyB,EAAE,KAAKqF,MAAM,CAAC;AAC1E,MAAA,MAAMM,aAAa,GAAG1E,QAAQ,GAAGwE,gBAAgB,CAAC,EAAEzF,EAAE;MACtD,MAAM4F,UAAU,GAAG3E,QAAQ,GAAGqE,UAAU,GAAG,CAAC,CAAC,EAAEtF,EAAE;AAEjD;MACA,IAAI2F,aAAa,KAAKC,UAAU,EAAE;AAChCL,QAAAA,IAAI,GAAGtE,QAAQ,CAACqE,UAAU,GAAG,CAAC,CAAC;AACjC,MAAA,CAAC,MAAM;AACLC,QAAAA,IAAI,GAAGtE,QAAQ,CAACwE,gBAAgB,GAAG,CAAC,CAAC;AACvC,MAAA;AAEA;AACA,MAAA,IAAIF,IAAI,IAAI,QAAQ,IAAIA,IAAI,EAAE;AAC5B;AACA,QAAA,MAAMM,OAAO,GAAGtE,aAAa,CAACqD,IAAI,CAAEC,CAAC,IAAKA,CAAC,CAAC7E,EAAE,KAAKuF,IAAI,EAAEvF,EAAE,CAAC;QAC5D,IACE6F,OAAO,KACNA,OAAO,CAACpD,MAAM,KAAKrB,MAAM,CAACoC,SAAS,IAAIqC,OAAO,CAACpD,MAAM,KAAKrB,MAAM,CAAC0E,IAAI,CAAC,IACvED,OAAO,CAACb,GAAG,EACX;AACAQ,UAAAA,WAAW,GAAG,MAAM;AACtB,QAAA;AACF,MAAA;AACAL,MAAAA,gBAAgB,CAAC,MAAK;QACpB,IAAII,IAAI,IAAI,OAAQA,IAAsB,CAACQ,KAAK,KAAK,UAAU,EAAE;UAC/D,OAAO;AAAE3D,YAAAA,GAAG,EAAEmD,IAAI;AAAES,YAAAA,MAAM,EAAER;WAAa;AAC3C,QAAA;AACA,QAAA,OAAOD,IAAI;AACb,MAAA,CAAC,CAAC;AACJ,IAAA;EACF,CAAC;EAED,MAAMU,aAAa,GAAGA,MAAK;IACzB,MAAMT,WAAW,GAAGN,aAAa;AACjC,IAAA,IAAIzE,qBAAqB,EAAE;MACzBC,wBAAwB,CAAC,IAAI,CAAC;AAC9B,MAAA;AACF,IAAA;AACA,IAAA,IAAI8E,WAAW,EAAE;AACf;AACA,MAAA,IACEjE,aAAa,CAACE,MAAM,KAAK,CAAC,IAC1BV,cAAc,CAACc,OAAO,IACtB,OAAOd,cAAc,CAACc,OAAO,CAACkE,KAAK,KAAK,UAAU,EAClD;AACAG,QAAAA,UAAU,CAAC,MAAK;AACdnF,UAAAA,cAAc,CAACc,OAAQ,CAACkE,KAAK,EAAE;QACjC,CAAC,EAAE,CAAC,CAAC;MACP,CAAC,MAAM,IACL,OAAOP,WAAW,KAAK,QAAQ,IAC/B,KAAK,IAAIA,WAAW,IACpBA,WAAW,CAACpD,GAAG,IACf,OAAOoD,WAAW,CAACpD,GAAG,CAAC2D,KAAK,KAAK,UAAU,EAC3C;AACAG,QAAAA,UAAU,CAAC,MAAK;AACd,UAAA,IAAIV,WAAW,CAACpD,GAAG,IAAI,OAAQoD,WAAW,CAACpD,GAAqB,CAAC2D,KAAK,KAAK,UAAU,EAAE;AACrF;YACCP,WAAW,CAACpD,GAAqB,CAAC2D,KAAK,CAACP,WAAW,CAACQ,MAAM,CAAC;AAC9D,UAAA;QACF,CAAC,EAAE,CAAC,CAAC;MACP,CAAC,MAAM,IAAIR,WAAW,IAAI,OAAQA,WAA6B,CAACO,KAAK,KAAK,UAAU,EAAE;AACpFG,QAAAA,UAAU,CAAC,MAAK;UACbV,WAA6B,CAACO,KAAK,EAAE;QACxC,CAAC,EAAE,CAAC,CAAC;AACP,MAAA;AACF,IAAA;EACF,CAAC;EAED,oBACEI,IAAA,CAAAC,QAAA,EAAA;AAAAC,IAAAA,QAAA,gBACEF,IAAA,CAAA,KAAA,EAAA;AACEG,MAAAA,IAAI,EAAC,OAAO;AACZtH,MAAAA,SAAS,EAAEuH,IAAI,CAAC,iBAAiB,EAAEvH,SAAS,EAAE;AAAEE,QAAAA;AAAQ,OAAE,CAAE;AAAA,MAAA,GACxDiB,eAAe;AAAAkG,MAAAA,QAAA,gBAEnBG,GAAA,CAAA,KAAA,EAAA;AACExH,QAAAA,SAAS,EAAC,0BAA0B;AACpC,QAAA,WAAA,EAAU,QAAQ;AAClB,QAAA,eAAA,EAAc,KAAK;AACnBsH,QAAAA,IAAI,EAAC,QAAQ;AAAAD,QAAAA,QAAA,EAEZ9E,aAAa,CAACgB,GAAG,CAAC,CAAChE,IAAI,EAAEkI,KAAK,kBAC7BD,GAAA,CAACE,UAAU,EAAA;UAETtE,GAAG,EAAGuE,EAAwB,IAAI;AAChC,YAAA,IACEA,EAAE,IACFA,EAAE,CAAC3G,EAAE,KAAKM,mBAAmB,EAAEN,EAAE,IACjC,CAACiB,QAAQ,CAAC2F,IAAI,CAAExE,GAAG,IAAKA,GAAG,IAAIA,GAAG,CAACpC,EAAE,KAAK2G,EAAE,CAAC3G,EAAE,CAAC,IAChD2G,EAAE,CAAClE,MAAM,KAAK,YAAY,EAC1B;AACAxB,cAAAA,QAAQ,CAAC4F,IAAI,CAACF,EAAE,CAAC;AACnB,YAAA;UACF,CAAE;AACFpI,UAAAA,IAAI,EAAEA,IAAK;UACXuI,gBAAgB,EAAE,CAAC3H,QAAS;AAC5B4H,UAAAA,SAAS,EACP,CAAC,CAAC,CAACrH,YAAY,IAAInB,IAAI,CAACkE,MAAM,KAAKrB,MAAM,CAACuB,MAAM,MAC/C,CAACpE,IAAI,CAACkE,MAAM,IAAI,CAACvB,iBAAiB,CAACwC,GAAG,CAACnF,IAAI,CAACkE,MAAM,CAAC,CACrD;UACDuE,QAAQ,EACNzI,IAAI,CAACkE,MAAM,KAAKrB,MAAM,CAACuB,MAAM,GACzB,YAAW;AACTjC,YAAAA,wBAAwB,CAACnC,IAAI,CAACyB,EAAE,CAAC;YACjC,MAAMwC,UAAU,CAACjE,IAAI,CAAC;AACtB0H,YAAAA,aAAa,EAAE;AACjB,UAAA,CAAC,GACD,MAAK;AACHvF,YAAAA,wBAAwB,CAACnC,IAAI,CAACyB,EAAE,CAAC;YACjCO,sBAAsB,CAAChC,IAAI,CAAC;UAC9B,CACL;AACDsB,UAAAA,UAAU,EAAEA,UAAW;AACvBoH,UAAAA,OAAO,EAAEA,MAAM7B,WAAW,CAAC7G,IAAI,CAACyB,EAAE;SAAE,EA9B/BzB,IAAI,CAACyB,EA8B0B,CAEvC;AAAC,OACC,CACL,EAAC,CAACb,QAAQ,IAAK,CAACA,QAAQ,IAAI,CAACoC,aAAa,CAACE,MAAO,kBAChD+E,GAAA,CAAA,KAAA,EAAA;AAAKxH,QAAAA,SAAS,EAAC,6DAA6D;QAAAqH,QAAA,eAC1EG,GAAA,CAACU,YAAY,EAAA;AACX9E,UAAAA,GAAG,EAAErB,cAAe;AACpBf,UAAAA,EAAE,EAAEA,EAAG;AACPE,UAAAA,iBAAiB,EAAEA,iBAAkB;AACrChB,UAAAA,QAAQ,EAAEyE,8BAA8B,EAAE,IAAIzE,QAAS;AACvDC,UAAAA,QAAQ,EAAEA,QAAS;AACnBC,UAAAA,SAAS,EAAEA,SAAU;AACrBE,UAAAA,SAAS,EAAEA,SAAU;AACrBE,UAAAA,WAAW,EAAEA,WAAY;AACzBM,UAAAA,QAAQ,EAAEA,QAAS;AACnBqH,UAAAA,WAAW,EAAEC,OAAO,CAAC7F,aAAa,CAACE,MAAM,CAAE;AAC3C4F,UAAAA,QAAQ,EAAExD;SAAS;AAEvB,OAAK,CACN;AAAA,KACE,CACL,eAAA2C,GAAA,CAACc,KAAK,EAAA;AACJC,MAAAA,KAAK,EACHtI,aAAa,EAAEsI,KAAK,KAAKxE,SAAS,GAC9B9D,aAAa,CAACsI,KAAK,GACnB1G,aAAa,CAACwD,QAAQ,CAACmD,gBAAgB,CAC5C;AACDC,MAAAA,IAAI,EACFxI,aAAa,EAAEwI,IAAI,KAAK1E,SAAS,GAC7B9D,aAAa,CAACwI,IAAI,GAClB5G,aAAa,CAACwD,QAAQ,CAACqD,eAAe,CAC3C;MACDC,IAAI,EAAE,CAAC,CAACrH,mBAAoB;MAC5BsH,MAAM,eACJzB,IAAA,CAAAC,QAAA,EAAA;QAAAC,QAAA,EAAA,cACEG,GAAA,CAACqB,MAAM,EAAA;UACLC,KAAK,EAAA,IAAA;UACLC,OAAO,EAAEA,MAAK;YACZxH,sBAAsB,CAAC,IAAI,CAAC;UAC9B,CAAE;UAAA8F,QAAA,EAEDpH,aAAa,EAAE+I,UAAU,IAAInH,aAAa,CAACwD,QAAQ,CAAC4D,2BAA2B;AAAC,SAC3E,CACR,eAAAzB,GAAA,CAACqB,MAAM,EAAA;UACLC,KAAK,EAAA,IAAA;UACLI,QAAQ,EAAEC,QAAQ,CAACC,SAAU;UAC7BC,IAAI,EAAEC,WAAW,CAACC,QAAS;AAC3BC,UAAAA,QAAQ,EAAElI,mBAAmB,GAAG,CAAC,GAAG,EAAG;UACvCyH,OAAO,EAAEA,MAAK;AACZ,YAAA,IAAIzH,mBAAmB,EAAE;cACvB,KAAKkC,UAAU,CAAClC,mBAAmB,CAAC;AACtC,YAAA;YACAC,sBAAsB,CAAC,IAAI,CAAC;YAC5BG,wBAAwB,CAAC,IAAI,CAAC;UAChC,CAAE;UAAA2F,QAAA,EAEDpH,aAAa,EAAEwJ,WAAW,IAAI5H,aAAa,CAACwD,QAAQ,CAACqE,4BAA4B;AAAC,SAC7E,CACV;AAAA,OAAA,CACD;AACDC,MAAAA,SAAS,EAAE1C,aAAc;MACzB2C,OAAO,EAAEA,MAAK;QACZrI,sBAAsB,CAAC,IAAI,CAAC;AAC9B,MAAA;AAAE,KAAA,CAEN;AAAA,GAAA,CAAG;AAEP;;;;"}
1
+ {"version":3,"file":"UploadInput.mjs","sources":["../../src/uploadInput/UploadInput.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport { useEffect, 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 * @default []\n */\n files?: readonly UploadedFile[];\n\n /**\n * The key of the file in the returned FormData object (default: file)\n * @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 allowed size limit are uploaded\n */\n sizeLimitErrorMessage?: string;\n} & {\n /** @default false */\n multiple?: UploadButtonProps['multiple'];\n /** @default ['.pdf,application/pdf', '.jpg,.jpeg,image/jpeg', '.png,image/png'] */\n fileTypes?: UploadButtonProps['fileTypes'];\n /** @default 5000 */\n sizeLimit?: UploadButtonProps['sizeLimit'];\n} & Pick<UploadButtonProps, 'disabled' | 'description' | 'id' | 'uploadButtonTitle'> & {\n onDownload?: UploadItemProps['onDownload'];\n } & 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 * Required id of the UploadItem component.\n */\n id: string | number;\n\n /**\n * Optional status of the UploadItem component.\n */\n status?: string;\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 [lastAttemptedDeleteId, setLastAttemptedDeleteId] = useState<string | number | null>(null);\n const mountedRef = useRef(false);\n const { formatMessage } = useIntl();\n const uploadInputRef = useRef<HTMLInputElement | null>(null);\n const fileRefs = useRef<(HTMLDivElement | UploadItemRef | 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 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 fileRefs.current = fileRefs.current.filter((ref) => ref && ref.id !== file.id);\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 const removeFile = async (file: UploadedFile) => {\n const { id: fileId, status } = file;\n fileRefs.current = fileRefs.current.filter((item) => item && item.id !== file.id);\n\n if (status === Status.FAILED) {\n removeFileFromList(file);\n return Promise.resolve();\n }\n\n if (onDeleteFile && fileId) {\n modifyFileInList(file, { status: Status.PROCESSING, error: undefined });\n\n return onDeleteFile(fileId)\n .then(() => {\n removeFileFromList(file);\n })\n .catch((error) => {\n modifyFileInList(file, { error: error as UploadError });\n });\n }\n };\n\n function handleFileUploadFailure(file: File, failureMessage: string) {\n const { name } = file;\n\n const failedUpload = {\n id: generateFileId(file),\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\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 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 (typeof sizeLimit === 'number' && !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 useEffect(() => {\n // Skip onFilesChange call on initial mount, only call on updates\n if (!mountedRef.current) {\n mountedRef.current = true;\n return;\n }\n\n if (onFilesChange) {\n onFilesChange([...uploadedFiles]);\n }\n }, [onFilesChange, uploadedFiles]);\n\n type NextFocusable =\n | HTMLDivElement\n | UploadItemRef\n | { ref: HTMLDivElement | UploadItemRef; target: 'button' | 'link' }\n | null;\n\n const [nextFocusable, setNextFocusable] = useState<NextFocusable>(null);\n\n const handleFocus = (fileId: string | number) => {\n fileRefs.current = fileRefs.current.filter((ref) => {\n return ref && ref.id !== markedFileForDelete?.id;\n });\n\n const filesCount = fileRefs.current.length;\n let next: UploadItemRef | HTMLDivElement | null = uploadInputRef.current;\n let focusTarget: 'button' | 'link' = 'button';\n\n // If there will be no files left after deletion, focus the upload button\n if (filesCount === 1) {\n next = uploadInputRef.current;\n setNextFocusable(next);\n return;\n }\n\n if (filesCount > 1) {\n const currentFileIndex = fileRefs.current.findIndex((file) => file?.id === fileId);\n const currentFileId = fileRefs.current?.[currentFileIndex]?.id;\n const lastFileId = fileRefs.current?.[filesCount - 1]?.id;\n\n // if last file, select a previous one\n if (currentFileId === lastFileId) {\n next = fileRefs.current[filesCount - 2];\n } else {\n next = fileRefs.current[currentFileIndex + 1];\n }\n\n // If next is an UploadItemRef, check if it has a URL (succeeded)\n if (next && 'status' in next) {\n // Find the file object for this ref\n const fileObj = uploadedFiles.find((f) => f.id === next?.id);\n if (\n fileObj &&\n (fileObj.status === Status.SUCCEEDED || fileObj.status === Status.DONE) &&\n fileObj.url\n ) {\n focusTarget = 'link';\n }\n }\n setNextFocusable(() => {\n if (next && typeof (next as UploadItemRef).focus === 'function') {\n return { ref: next, target: focusTarget };\n }\n return next;\n });\n }\n };\n\n const handleRefocus = () => {\n const focusTarget = nextFocusable;\n if (lastAttemptedDeleteId) {\n setLastAttemptedDeleteId(null);\n return;\n }\n if (focusTarget) {\n // If there are no files left, focus the upload button\n if (\n uploadedFiles.length === 0 &&\n uploadInputRef.current &&\n typeof uploadInputRef.current.focus === 'function'\n ) {\n setTimeout(() => {\n uploadInputRef.current?.focus();\n }, 0);\n } else if (\n typeof focusTarget === 'object' &&\n 'ref' in focusTarget &&\n focusTarget.ref &&\n typeof focusTarget.ref.focus === 'function'\n ) {\n setTimeout(() => {\n if (focusTarget.ref && typeof (focusTarget.ref as UploadItemRef).focus === 'function') {\n // @ts-expect-error: focus may not exist on all possible ref types, but is safe here\n (focusTarget.ref as UploadItemRef).focus(focusTarget.target);\n }\n }, 0);\n } else if (focusTarget && typeof (focusTarget as UploadItemRef).focus === 'function') {\n setTimeout(() => {\n (focusTarget as UploadItemRef).focus();\n }, 0);\n }\n }\n };\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) => (\n <UploadItem\n key={file.id}\n ref={(el: UploadItemRef | null) => {\n if (\n el &&\n el.id !== markedFileForDelete?.id &&\n !fileRefs.current.some((ref) => ref?.id === el.id) &&\n el.status !== 'processing'\n ) {\n fileRefs.current.push(el);\n }\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 ? async () => {\n setLastAttemptedDeleteId(file.id);\n await removeFile(file);\n handleRefocus();\n }\n : () => {\n setLastAttemptedDeleteId(file.id);\n setMarkedFileForDelete(file);\n }\n }\n onDownload={onDownload}\n onFocus={() => handleFocus(file.id)}\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 // eslint-disable-next-line react-hooks/refs -- Function reads ref for file count check\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 tabIndex={markedFileForDelete ? 0 : -1}\n onClick={() => {\n if (markedFileForDelete) {\n void removeFile(markedFileForDelete);\n }\n setMarkedFileForDelete(null);\n setLastAttemptedDeleteId(null);\n }}\n >\n {deleteConfirm?.confirmText || formatMessage(MESSAGES.deleteModalConfirmButtonText)}\n </Button>\n </>\n }\n onUnmount={handleRefocus}\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","lastAttemptedDeleteId","setLastAttemptedDeleteId","mountedRef","useRef","formatMessage","useIntl","uploadInputRef","fileRefs","PROGRESS_STATUSES","Set","Status","PENDING","PROCESSING","uploadedFiles","setUploadedFiles","length","uploadedFilesListReference","updateFileList","updateFn","current","addFileToList","recentUploadedFile","list","removeFileFromList","filter","fileInList","ref","modifyFileInList","updates","map","removeFile","fileId","status","item","FAILED","Promise","resolve","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","f","append","pendingFile","url","useEffect","nextFocusable","setNextFocusable","handleFocus","filesCount","next","focusTarget","currentFileIndex","findIndex","currentFileId","lastFileId","fileObj","DONE","focus","target","handleRefocus","setTimeout","_jsxs","_Fragment","children","role","clsx","_jsx","UploadItem","el","some","push","singleFileUpload","canDelete","onDelete","onFocus","UploadButton","withEntries","Boolean","onChange","Modal","title","deleteModalTitle","body","deleteModalBody","open","footer","Button","block","onClick","cancelText","deleteModalCancelButtonText","priority","Priority","SECONDARY","type","ControlType","NEGATIVE","tabIndex","confirmText","deleteModalConfirmButtonText","onUnmount","onClose"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transferwise/components",
3
- "version": "46.140.0",
3
+ "version": "46.141.0",
4
4
  "description": "Neptune React components",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -73,7 +73,7 @@
73
73
  "monaco-editor": "^0.55.1",
74
74
  "monaco-editor-webpack-plugin": "^7.1.1",
75
75
  "@wise/art": "^2.30.1",
76
- "@wise/eslint-config": "^13.3.0",
76
+ "@wise/eslint-config": "^14.2.1",
77
77
  "babel-plugin-formatjs": "^10.5.41",
78
78
  "eslint": "^9.39.4",
79
79
  "eslint-plugin-storybook": "^10.3.6",
@@ -111,7 +111,7 @@
111
111
  "@react-aria/focus": "^3.22.0",
112
112
  "@react-aria/overlays": "^3.32.0",
113
113
  "@transferwise/formatting": "^2.14.1",
114
- "@transferwise/neptune-tokens": "^8.21.0",
114
+ "@transferwise/neptune-tokens": "^8.23.0",
115
115
  "@transferwise/neptune-validation": "^3.3.3",
116
116
  "clsx": "^2.1.1",
117
117
  "commonmark": "^0.31.2",
@@ -1,6 +1,5 @@
1
- import { BadgeProps } from '../badge';
2
- import { Sentiment, Size, ProfileType } from '../common';
3
- import { render, screen, mockMatchMedia } from '../test-utils';
1
+ import { Sentiment } from '../common';
2
+ import { render, screen, mockMatchMedia, fireEvent } from '../test-utils';
4
3
 
5
4
  import AvatarWrapper from '.';
6
5
 
@@ -60,6 +59,37 @@ describe('FlowNavigationAvatar', () => {
60
59
  expect(screen.getByLabelText('test')).toBeInTheDocument();
61
60
  });
62
61
  });
62
+
63
+ describe('with image URL', () => {
64
+ it('falls back to initials when image fails to load', () => {
65
+ const { container } = render(<AvatarWrapper name="John Doe" url="invalid-url.jpg" />);
66
+
67
+ const img = container.querySelector('img');
68
+ if (img) {
69
+ fireEvent.error(img);
70
+ }
71
+
72
+ expect(screen.getByText('JD')).toBeInTheDocument();
73
+ });
74
+
75
+ it('resets error state when url prop changes', () => {
76
+ const { container, rerender } = render(
77
+ <AvatarWrapper name="John Doe" url="invalid-url-1.jpg" />,
78
+ );
79
+
80
+ const img = container.querySelector('img');
81
+ if (img) {
82
+ fireEvent.error(img);
83
+ }
84
+
85
+ expect(screen.getByText('JD')).toBeInTheDocument();
86
+
87
+ rerender(<AvatarWrapper name="John Doe" url="valid-url.jpg" />);
88
+
89
+ const newImg = container.querySelector('img');
90
+ expect(newImg).toHaveAttribute('src', 'valid-url.jpg');
91
+ });
92
+ });
63
93
  });
64
94
  });
65
95
  });
@@ -1,5 +1,5 @@
1
1
  import { Person, Briefcase as BriefcaseIcon } from '@transferwise/icons';
2
- import { useState, useEffect } from 'react';
2
+ import { useState } from 'react';
3
3
 
4
4
  import Avatar, { AvatarProps, AvatarType } from '../avatar';
5
5
  import Badge, { BadgeProps } from '../badge';
@@ -91,11 +91,10 @@ const AvatarWrapper = ({
91
91
  avatarProps,
92
92
  badgeProps,
93
93
  }: AvatarWrapperProps) => {
94
- const [hasImageLoadError, setImageLoadError] = useState(false);
95
- const isBusinessProfile = profileType === ProfileType.BUSINESS;
94
+ const [errorUrl, setErrorUrl] = useState<string | undefined>(undefined);
96
95
 
97
- // Reset the errored state when url changes
98
- useEffect(() => setImageLoadError(false), [url]);
96
+ const hasImageLoadError = errorUrl === url;
97
+ const isBusinessProfile = profileType === ProfileType.BUSINESS;
99
98
 
100
99
  const getAvatarProps = () => {
101
100
  let updatedAvatarProps = avatarProps;
@@ -105,7 +104,7 @@ const AvatarWrapper = ({
105
104
  if (url && !hasImageLoadError) {
106
105
  return {
107
106
  type: AvatarType.THUMBNAIL,
108
- children: <img src={url} alt="" onError={() => setImageLoadError(true)} />,
107
+ children: <img src={url} alt="" onError={() => setErrorUrl(url)} />,
109
108
  ...updatedAvatarProps,
110
109
  };
111
110
  }
@@ -177,7 +177,7 @@ const LegacyButton = forwardRef<ButtonReferenceType, LegacyButtonProps>(
177
177
 
178
178
  return (
179
179
  <Element
180
- ref={ref as React.Ref<ButtonReferenceType>}
180
+ ref={ref}
181
181
  className={classes}
182
182
  onClick={handleClick(onClick)}
183
183
  {...props}
@@ -51,7 +51,7 @@ export const AllVariants: Story = {
51
51
  >
52
52
  <Button
53
53
  v2
54
- priority={priority as ButtonPriority}
54
+ priority={priority}
55
55
  size={size}
56
56
  addonStart={{ type: 'avatar', value: [{ asset: <Freeze /> }] }}
57
57
  addonEnd={{ type: 'icon', value: <ArrowRight /> }}
@@ -62,7 +62,7 @@ export const AllVariants: Story = {
62
62
  <Button
63
63
  className="m-t-1 m-b-1"
64
64
  v2
65
- priority={priority as ButtonPriority}
65
+ priority={priority}
66
66
  size={size}
67
67
  addonStart={{
68
68
  type: 'avatar',
@@ -76,7 +76,7 @@ export const AllVariants: Story = {
76
76
  </Button>
77
77
  <Button
78
78
  v2
79
- priority={priority as ButtonPriority}
79
+ priority={priority}
80
80
  size={size}
81
81
  addonStart={{ type: 'avatar', value: [{ asset: <Freeze /> }] }}
82
82
  addonEnd={{ type: 'icon', value: <ArrowRight /> }}
@@ -19,7 +19,7 @@ describe('useContainerSize', () => {
19
19
  resizeObserverCallback = callback;
20
20
  const instance = new OriginalResizeObserver(callback);
21
21
  return instance;
22
- }) as unknown as typeof ResizeObserver;
22
+ });
23
23
  });
24
24
 
25
25
  afterEach(() => {
@@ -22,7 +22,11 @@ export const useHasIntersected = ({
22
22
  elRef: React.RefObject<HTMLElement>;
23
23
  loading?: 'eager' | 'lazy';
24
24
  }) => {
25
- const [hasIntersected, setHasIntersected] = useState(false);
25
+ // Initialize as true if IntersectionObserver is not supported
26
+ // Note: We can't check elRef.current here as it may not be set yet on first render
27
+ const [hasIntersected, setHasIntersected] = useState(() => {
28
+ return typeof window === 'undefined' || !window.IntersectionObserver;
29
+ });
26
30
 
27
31
  const { current } = elRef || {};
28
32
 
@@ -47,9 +51,13 @@ export const useHasIntersected = ({
47
51
  let didCancel = false;
48
52
 
49
53
  // Check if window is defined for SSR and Old browsers fallback
50
- if (typeof window === 'undefined' || !window.IntersectionObserver || !isValidReference()) {
51
- setHasIntersected(true);
52
- } else if (current && !didCancel) {
54
+ if (
55
+ typeof window !== 'undefined' &&
56
+ window.IntersectionObserver &&
57
+ isValidReference() &&
58
+ current &&
59
+ !didCancel
60
+ ) {
53
61
  observer = new IntersectionObserver(handleOnIntersect, ObserverParams);
54
62
  observer.observe(current);
55
63
  }
@@ -86,12 +86,15 @@ export const LiveRegion = ({
86
86
  (typeof children === 'string' || typeof children === 'number' ? children : undefined);
87
87
 
88
88
  useEffect(() => {
89
- setShouldAnnounce(false);
90
-
91
89
  if (ariaLive === 'off') {
92
90
  return;
93
91
  }
94
92
 
93
+ // Reset announcement state, then schedule new announcement
94
+ // This two-step process ensures screen readers re-announce the content
95
+ // eslint-disable-next-line react-hooks/set-state-in-effect -- Deliberately resetting state to force re-announcement for screen readers
96
+ setShouldAnnounce(false);
97
+
95
98
  const timeoutId = window.setTimeout(
96
99
  () => setShouldAnnounce(true),
97
100
  scheduleAnnouncement(ariaLive),
@@ -134,10 +134,10 @@ const DateInput = ({
134
134
  const monthBeforeDay = MDY.has(locale);
135
135
  const yearFirst = YMD.has(locale);
136
136
 
137
- dayLabel ||= formatMessage(messages.dayLabel);
138
- monthLabel ||= formatMessage(messages.monthLabel);
139
- yearLabel ||= formatMessage(messages.yearLabel);
140
- placeholders = {
137
+ const resolvedDayLabel = dayLabel || formatMessage(messages.dayLabel);
138
+ const resolvedMonthLabel = monthLabel || formatMessage(messages.monthLabel);
139
+ const resolvedYearLabel = yearLabel || formatMessage(messages.yearLabel);
140
+ const resolvedPlaceholders = {
141
141
  day: placeholders?.day || formatMessage(messages.dayPlaceholder),
142
142
  month: placeholders?.month || formatMessage(messages.monthLabel),
143
143
  year: placeholders?.year || formatMessage(messages.yearPlaceholder),
@@ -186,14 +186,14 @@ const DateInput = ({
186
186
  const getSelectElement = () => {
187
187
  return (
188
188
  <label className="d-flex flex-column">
189
- <Body type={Typography.BODY_DEFAULT}>{monthLabel}</Body>
189
+ <Body type={Typography.BODY_DEFAULT}>{resolvedMonthLabel}</Body>
190
190
  <SelectInput
191
191
  triggerRef={monthRef}
192
192
  id={`${id}:month`}
193
193
  parentId={DATE_INPUT_PARENT_ID}
194
194
  name="month"
195
195
  disabled={disabled}
196
- placeholder={placeholders?.month}
196
+ placeholder={resolvedPlaceholders.month}
197
197
  items={Array.from({ length: 12 }, (_, index) => ({ type: 'option', value: index }))}
198
198
  size={size}
199
199
  value={month}
@@ -295,7 +295,7 @@ const DateInput = ({
295
295
  return (
296
296
  <div className="col-sm-3 tw-date--day">
297
297
  <label>
298
- <Body type={Typography.BODY_DEFAULT}>{dayLabel}</Body>
298
+ <Body type={Typography.BODY_DEFAULT}>{resolvedDayLabel}</Body>
299
299
  <div className={`input-group input-group-${size} ${disabled ? 'disabled' : ''}`}>
300
300
  <Input
301
301
  ref={dayRef}
@@ -306,7 +306,7 @@ const DateInput = ({
306
306
  name="day"
307
307
  autoComplete={dayAutoComplete}
308
308
  value={displayDay || ''}
309
- placeholder={placeholders?.day}
309
+ placeholder={resolvedPlaceholders.day}
310
310
  disabled={disabled}
311
311
  min={1}
312
312
  max={31}
@@ -323,7 +323,7 @@ const DateInput = ({
323
323
  return (
324
324
  <div className="col-sm-4 tw-date--year">
325
325
  <label>
326
- <Body type={Typography.BODY_DEFAULT}>{yearLabel}</Body>
326
+ <Body type={Typography.BODY_DEFAULT}>{resolvedYearLabel}</Body>
327
327
  <div className={`input-group input-group-${size} ${disabled ? 'disabled' : ''}`}>
328
328
  <Input
329
329
  ref={yearRef}
@@ -333,7 +333,7 @@ const DateInput = ({
333
333
  pattern="[0-9]*"
334
334
  name="year"
335
335
  autoComplete={yearAutoComplete}
336
- placeholder={placeholders?.year}
336
+ placeholder={resolvedPlaceholders.year}
337
337
  value={displayYear || ''}
338
338
  disabled={disabled}
339
339
  min={0}
@@ -6,6 +6,7 @@ import { useState } from 'react';
6
6
  import DateLookup, { type DateLookupProps } from './DateLookup';
7
7
  import { Size } from '../common';
8
8
  import { withVariantConfig } from '../../.storybook/helpers';
9
+ import { Field } from '../field/Field';
9
10
 
10
11
  export default {
11
12
  component: DateLookup,
@@ -142,3 +143,18 @@ export const Basic400Zoom: StoryObj<typeof DateLookup> = {
142
143
  },
143
144
  }),
144
145
  };
146
+
147
+ export const Disabled: StoryObj<typeof DateLookup> = {
148
+ render: () => (
149
+ <Field label="Start date">
150
+ <DateLookup
151
+ disabled
152
+ clearable={false}
153
+ value={new Date(2024, 0, 14, 12, 0, 0)}
154
+ placeholder="Select date"
155
+ monthFormat="long"
156
+ onChange={props.onChange}
157
+ />
158
+ </Field>
159
+ ),
160
+ };
@@ -322,7 +322,7 @@ class DateLookup extends PureComponent<DateLookupPropsWithInputAttributes, DateL
322
322
  aria-labelledby={id}
323
323
  aria-invalid={inputAttributes?.['aria-invalid']}
324
324
  aria-describedby={inputAttributes?.['aria-describedby']}
325
- className="input-group"
325
+ className={clsx('input-group', disabled && 'disabled')}
326
326
  onKeyDown={this.handleKeyDown}
327
327
  >
328
328
  <OverlayIdProvider open={open}>
@@ -43,11 +43,7 @@ const MonthCalendarTable = ({
43
43
  };
44
44
 
45
45
  const isActive = (month: number) => {
46
- return !!(
47
- selectedDate &&
48
- month === selectedDate.getMonth() &&
49
- viewYear === selectedDate.getFullYear()
50
- );
46
+ return !!(month === selectedDate?.getMonth() && viewYear === selectedDate?.getFullYear());
51
47
  };
52
48
 
53
49
  const isThisMonth = (month: number) => {
@@ -43,7 +43,7 @@ const YearCalendarTable = ({
43
43
  };
44
44
 
45
45
  const isActive = (year: number) => {
46
- return !!(selectedDate && year === selectedDate.getFullYear());
46
+ return !!(year === selectedDate?.getFullYear());
47
47
  };
48
48
 
49
49
  const isThisYear = (year: number) => {
@@ -72,7 +72,7 @@ export type Props = {
72
72
  export default function ExpressiveMoneyInput({
73
73
  label,
74
74
  currency,
75
- currencySelector = { options: [] } as DefaultCurrencySelectorInstanceType,
75
+ currencySelector = { options: [] },
76
76
  amount,
77
77
  onAmountChange,
78
78
  className,