@transferwise/components 46.100.2 → 46.101.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.
- package/build/i18n/en.json +2 -0
- package/build/i18n/en.json.js +2 -0
- package/build/i18n/en.json.js.map +1 -1
- package/build/i18n/en.json.mjs +2 -0
- package/build/i18n/en.json.mjs.map +1 -1
- package/build/types/test-utils/index.d.ts +4 -0
- package/build/types/test-utils/index.d.ts.map +1 -1
- package/build/types/upload/Upload.d.ts +6 -2
- package/build/types/upload/Upload.d.ts.map +1 -1
- package/build/types/upload/Upload.messages.d.ts +8 -0
- package/build/types/upload/Upload.messages.d.ts.map +1 -1
- package/build/types/uploadInput/UploadInput.d.ts +1 -1
- package/build/types/uploadInput/uploadButton/UploadButton.d.ts +4 -2
- package/build/types/uploadInput/uploadButton/UploadButton.d.ts.map +1 -1
- package/build/upload/Upload.js +16 -9
- package/build/upload/Upload.js.map +1 -1
- package/build/upload/Upload.messages.js +6 -0
- package/build/upload/Upload.messages.js.map +1 -1
- package/build/upload/Upload.messages.mjs +6 -0
- package/build/upload/Upload.messages.mjs.map +1 -1
- package/build/upload/Upload.mjs +16 -9
- package/build/upload/Upload.mjs.map +1 -1
- package/build/uploadInput/UploadInput.js +1 -1
- package/build/uploadInput/UploadInput.js.map +1 -1
- package/build/uploadInput/UploadInput.mjs +1 -1
- package/build/uploadInput/UploadInput.mjs.map +1 -1
- package/build/uploadInput/uploadButton/UploadButton.js +7 -4
- package/build/uploadInput/uploadButton/UploadButton.js.map +1 -1
- package/build/uploadInput/uploadButton/UploadButton.mjs +7 -4
- package/build/uploadInput/uploadButton/UploadButton.mjs.map +1 -1
- package/package.json +2 -2
- package/src/i18n/en.json +2 -0
- package/src/upload/Upload.messages.ts +8 -0
- package/src/upload/Upload.spec.tsx +6 -0
- package/src/upload/Upload.story.tsx +118 -3
- package/src/upload/Upload.tests.story.tsx +5 -3
- package/src/upload/Upload.tsx +24 -15
- package/src/uploadInput/UploadInput.tests.story.tsx +7 -0
- package/src/uploadInput/UploadInput.tsx +2 -2
- package/src/uploadInput/uploadButton/UploadButton.spec.tsx +6 -0
- package/src/uploadInput/uploadButton/UploadButton.tsx +12 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UploadButton.mjs","sources":["../../../src/uploadInput/uploadButton/UploadButton.tsx"],"sourcesContent":["import { PlusCircle as PlusIcon, Upload as UploadIcon } from '@transferwise/icons';\nimport { clsx } from 'clsx';\nimport {\n ChangeEvent,\n DragEvent,\n useRef,\n useState,\n forwardRef,\n useImperativeHandle,\n ForwardedRef,\n} from 'react';\nimport { useIntl } from 'react-intl';\n\nimport Body from '../../body';\nimport { FileType, Typography } from '../../common';\n\nimport MESSAGES from './UploadButton.messages';\nimport { DEFAULT_SIZE_LIMIT, imageFileTypes } from './defaults';\nimport getAllowedFileTypes from './getAllowedFileTypes';\n\ntype AllowedFileTypes = string | readonly string[] | readonly FileType[];\nexport type UploadButtonProps = {\n /**\n * Disable the upload button if your app is not yet ready to accept uploads\n */\n disabled?: boolean;\n\n /**\n * Should be true, if the UploadInput has at least 1\n * file (valid or invalid) listed.\n */\n withEntries?: boolean;\n\n /**\n * Allow multiple file uploads\n */\n multiple?: boolean;\n\n /**\n * List of allowed filetypes, eg. '*' | '.zip,application/zip' | ['.jpg,.jpeg,image/jpeg', '.png,image/png'] (default: image files + PDF)\n */\n fileTypes?: AllowedFileTypes;\n\n /**\n * Size limit in KBs 1000 KB = 1 MB (default: 5000 KB)\n */\n sizeLimit?: number;\n\n /**\n * Description for the upload button\n */\n description?: string | undefined;\n\n /**\n * Maximum number of files allowed, if provided, shows error below file item\n */\n maxFiles?: number;\n\n /**\n * Called when some files were successfully selected\n *\n * @param files\n */\n onChange: (files: FileList) => void;\n\n /**\n * Id for the upload input\n */\n id?: string;\n\n /**\n * Title for the upload button\n */\n uploadButtonTitle?: string;\n};\n\nexport enum TEST_IDS {\n uploadInput = 'uploadInput',\n mediaBody = 'mediaBody',\n}\n\nconst onDragOver = (event: DragEvent): void => {\n event.preventDefault();\n};\n\nconst DEFAULT_FILE_INPUT_ID = 'np-upload-button';\nconst UploadButton = forwardRef<HTMLInputElement | null, UploadButtonProps>(\n (\n {\n disabled,\n withEntries,\n multiple,\n description,\n fileTypes = imageFileTypes,\n sizeLimit = DEFAULT_SIZE_LIMIT,\n maxFiles,\n onChange,\n id = DEFAULT_FILE_INPUT_ID,\n uploadButtonTitle,\n },\n ref: ForwardedRef<HTMLInputElement | null>,\n ) => {\n const { formatMessage } = useIntl();\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n useImperativeHandle(ref, () => {\n if (!inputRef.current) {\n throw new Error('inputRef.current is null');\n }\n return inputRef.current;\n }, []);\n\n const [isDropping, setIsDropping] = useState(false);\n\n const dragCounter = useRef(0);\n\n const reset = (): void => {\n dragCounter.current = 0;\n setIsDropping(false);\n };\n\n const onDragLeave = (event: DragEvent): void => {\n event.preventDefault();\n dragCounter.current -= 1;\n if (dragCounter.current === 0) {\n setIsDropping(false);\n }\n };\n\n const onDragEnter = (event: DragEvent): void => {\n event.preventDefault();\n dragCounter.current += 1;\n if (dragCounter.current === 1) {\n setIsDropping(true);\n }\n };\n\n const onDrop = (event: DragEvent): void => {\n event.preventDefault();\n reset();\n if (event.dataTransfer && event.dataTransfer.files && event.dataTransfer.files[0]) {\n onChange(event.dataTransfer.files);\n }\n };\n\n const filesSelected = (event: ChangeEvent<HTMLInputElement>): void => {\n const { files } = event.target;\n\n if (files) {\n onChange(files);\n\n if (inputRef.current) {\n inputRef.current.value = '';\n }\n }\n };\n\n const getFileTypesDescription = (): string => {\n if (fileTypes === '*') {\n return fileTypes;\n }\n\n return getAllowedFileTypes(Array.isArray(fileTypes) ? fileTypes : [fileTypes]).join(', ');\n };\n\n function getDescription() {\n if (description) {\n return description;\n }\n\n const fileTypesDescription = getFileTypesDescription();\n\n const derivedFileDescription =\n fileTypesDescription === '*' ? formatMessage(MESSAGES.allFileTypes) : fileTypesDescription;\n\n return formatMessage(MESSAGES.instructions, {\n fileTypes: derivedFileDescription,\n size: Math.round(sizeLimit / 1000),\n });\n }\n\n function getAcceptedTypes(): Pick<React.ComponentPropsWithoutRef<'input'>, 'accept'> {\n const areAllFilesAllowed = getFileTypesDescription() === '*';\n\n if (areAllFilesAllowed) {\n return {}; // file input by default allows all files\n }\n\n if (Array.isArray(fileTypes)) {\n return { accept: fileTypes.join(',') };\n }\n\n return { accept: fileTypes as string };\n }\n\n function renderDescription() {\n return (\n <Body className=\"np-upload-input__text\">\n {getDescription()}\n {maxFiles && (\n <>\n <br />\n {formatMessage(MESSAGES.maximumFiles, { maxFiles })}\n </>\n )}\n </Body>\n );\n }\n\n function renderButtonTitle() {\n if (uploadButtonTitle) {\n return uploadButtonTitle;\n }\n return formatMessage(multiple ? MESSAGES.uploadFiles : MESSAGES.uploadFile);\n }\n\n return (\n <label\n className={clsx(\n 'np-upload-input__upload-button',\n `np-upload-input__upload-button--${disabled ? 'disabled' : 'enabled'}`,\n `np-upload-input__upload-button--${withEntries ? 'with-entries' : 'without-entries'}`,\n {\n 'is-dropping': isDropping,\n },\n )}\n htmlFor={id}\n {...(!disabled && { onDragEnter, onDragLeave, onDrop, onDragOver })}\n >\n <span className=\"np-upload-input__icon\">\n <UploadIcon size={24} className=\"text-link\" />\n </span>\n <div className=\"np-upload-input__item-content\" data-testid={TEST_IDS.mediaBody}>\n <Body type={Typography.BODY_LARGE_BOLD} className=\"np-upload-input__title\">\n {renderButtonTitle()}\n </Body>\n {renderDescription()}\n </div>\n <input\n className=\"np-upload-input__upload-button-input sr-only\"\n type=\"file\"\n id={id}\n {...getAcceptedTypes()}\n {...(multiple && { multiple: true })}\n ref={inputRef}\n disabled={disabled}\n name=\"file-upload\"\n data-testid={TEST_IDS.uploadInput}\n onChange={filesSelected}\n />\n {isDropping && (\n <div\n className={clsx(\n 'np-upload-input__drop-file-overlay',\n 'droppable-card',\n 'droppable-dropping-card',\n 'droppable-card-content',\n )}\n >\n <PlusIcon className=\"m-x-1\" size={24} />\n <div>{formatMessage(MESSAGES.dropFile)}</div>\n </div>\n )}\n </label>\n );\n },\n);\n\nUploadButton.displayName = 'UploadButton';\n\nexport default UploadButton;\n"],"names":["TEST_IDS","onDragOver","event","preventDefault","DEFAULT_FILE_INPUT_ID","UploadButton","forwardRef","disabled","withEntries","multiple","description","fileTypes","imageFileTypes","sizeLimit","DEFAULT_SIZE_LIMIT","maxFiles","onChange","id","uploadButtonTitle","ref","formatMessage","useIntl","inputRef","useRef","useImperativeHandle","current","Error","isDropping","setIsDropping","useState","dragCounter","reset","onDragLeave","onDragEnter","onDrop","dataTransfer","files","filesSelected","target","value","getFileTypesDescription","getAllowedFileTypes","Array","isArray","join","getDescription","fileTypesDescription","derivedFileDescription","MESSAGES","allFileTypes","instructions","size","Math","round","getAcceptedTypes","areAllFilesAllowed","accept","renderDescription","_jsxs","Body","className","children","_Fragment","_jsx","maximumFiles","renderButtonTitle","uploadFiles","uploadFile","clsx","htmlFor","UploadIcon","mediaBody","type","Typography","BODY_LARGE_BOLD","name","uploadInput","PlusIcon","dropFile","displayName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"UploadButton.mjs","sources":["../../../src/uploadInput/uploadButton/UploadButton.tsx"],"sourcesContent":["import { PlusCircle as PlusIcon, Upload as UploadIcon } from '@transferwise/icons';\nimport { clsx } from 'clsx';\nimport {\n ChangeEvent,\n DragEvent,\n useRef,\n useState,\n forwardRef,\n useImperativeHandle,\n ForwardedRef,\n} from 'react';\nimport { useIntl } from 'react-intl';\n\nimport Body from '../../body';\nimport { FileType, Typography } from '../../common';\n\nimport MESSAGES from './UploadButton.messages';\nimport { DEFAULT_SIZE_LIMIT, imageFileTypes } from './defaults';\nimport getAllowedFileTypes from './getAllowedFileTypes';\n\ntype AllowedFileTypes = string | readonly string[] | readonly FileType[];\nexport type UploadButtonProps = {\n /**\n * Disable the upload button if your app is not yet ready to accept uploads\n */\n disabled?: boolean;\n\n /**\n * Should be true, if the UploadInput has at least 1\n * file (valid or invalid) listed.\n */\n withEntries?: boolean;\n\n /**\n * Allow multiple file uploads\n */\n multiple?: boolean;\n\n /**\n * List of allowed filetypes, eg. '*' | '.zip,application/zip' | ['.jpg,.jpeg,image/jpeg', '.png,image/png'] (default: image files + PDF)\n */\n fileTypes?: AllowedFileTypes;\n\n /**\n * Size limit in KBs (1000 KB = 1 MB).\n * If set to `null`, no size limit will be applied.\n * @default 5000\n */\n sizeLimit?: number | null;\n\n /**\n * Description for the upload button\n */\n description?: string | undefined;\n\n /**\n * Maximum number of files allowed, if provided, shows error below file item\n */\n maxFiles?: number;\n\n /**\n * Called when some files were successfully selected\n *\n * @param files\n */\n onChange: (files: FileList) => void;\n\n /**\n * Id for the upload input\n */\n id?: string;\n\n /**\n * Title for the upload button\n */\n uploadButtonTitle?: string;\n};\n\nexport enum TEST_IDS {\n uploadInput = 'uploadInput',\n mediaBody = 'mediaBody',\n}\n\nconst onDragOver = (event: DragEvent): void => {\n event.preventDefault();\n};\n\nconst DEFAULT_FILE_INPUT_ID = 'np-upload-button';\nconst UploadButton = forwardRef<HTMLInputElement | null, UploadButtonProps>(\n (\n {\n disabled,\n withEntries,\n multiple,\n description,\n fileTypes = imageFileTypes,\n sizeLimit = DEFAULT_SIZE_LIMIT,\n maxFiles,\n onChange,\n id = DEFAULT_FILE_INPUT_ID,\n uploadButtonTitle,\n },\n ref: ForwardedRef<HTMLInputElement | null>,\n ) => {\n const { formatMessage } = useIntl();\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n useImperativeHandle(ref, () => {\n if (!inputRef.current) {\n throw new Error('inputRef.current is null');\n }\n return inputRef.current;\n }, []);\n\n const [isDropping, setIsDropping] = useState(false);\n\n const dragCounter = useRef(0);\n\n const reset = (): void => {\n dragCounter.current = 0;\n setIsDropping(false);\n };\n\n const onDragLeave = (event: DragEvent): void => {\n event.preventDefault();\n dragCounter.current -= 1;\n if (dragCounter.current === 0) {\n setIsDropping(false);\n }\n };\n\n const onDragEnter = (event: DragEvent): void => {\n event.preventDefault();\n dragCounter.current += 1;\n if (dragCounter.current === 1) {\n setIsDropping(true);\n }\n };\n\n const onDrop = (event: DragEvent): void => {\n event.preventDefault();\n reset();\n if (event.dataTransfer && event.dataTransfer.files && event.dataTransfer.files[0]) {\n onChange(event.dataTransfer.files);\n }\n };\n\n const filesSelected = (event: ChangeEvent<HTMLInputElement>): void => {\n const { files } = event.target;\n\n if (files) {\n onChange(files);\n\n if (inputRef.current) {\n inputRef.current.value = '';\n }\n }\n };\n\n const getFileTypesDescription = (): string => {\n if (fileTypes === '*') {\n return fileTypes;\n }\n\n return getAllowedFileTypes(Array.isArray(fileTypes) ? fileTypes : [fileTypes]).join(', ');\n };\n\n function getDescription() {\n if (description) {\n return description;\n }\n\n const fileTypesDescription = getFileTypesDescription();\n\n const derivedFileDescription =\n fileTypesDescription === '*' ? formatMessage(MESSAGES.allFileTypes) : fileTypesDescription;\n\n if (typeof sizeLimit === 'number') {\n return formatMessage(MESSAGES.instructions, {\n fileTypes: derivedFileDescription,\n size: Math.round(sizeLimit / 1000),\n });\n }\n\n return derivedFileDescription;\n }\n\n function getAcceptedTypes(): Pick<React.ComponentPropsWithoutRef<'input'>, 'accept'> {\n const areAllFilesAllowed = getFileTypesDescription() === '*';\n\n if (areAllFilesAllowed) {\n return {}; // file input by default allows all files\n }\n\n if (Array.isArray(fileTypes)) {\n return { accept: fileTypes.join(',') };\n }\n\n return { accept: fileTypes as string };\n }\n\n function renderDescription() {\n return (\n <Body className=\"np-upload-input__text\">\n {getDescription()}\n {maxFiles && (\n <>\n <br />\n {formatMessage(MESSAGES.maximumFiles, { maxFiles })}\n </>\n )}\n </Body>\n );\n }\n\n function renderButtonTitle() {\n if (uploadButtonTitle) {\n return uploadButtonTitle;\n }\n return formatMessage(multiple ? MESSAGES.uploadFiles : MESSAGES.uploadFile);\n }\n\n return (\n <label\n className={clsx(\n 'np-upload-input__upload-button',\n `np-upload-input__upload-button--${disabled ? 'disabled' : 'enabled'}`,\n `np-upload-input__upload-button--${withEntries ? 'with-entries' : 'without-entries'}`,\n {\n 'is-dropping': isDropping,\n },\n )}\n htmlFor={id}\n {...(!disabled && { onDragEnter, onDragLeave, onDrop, onDragOver })}\n >\n <span className=\"np-upload-input__icon\">\n <UploadIcon size={24} className=\"text-link\" />\n </span>\n <div className=\"np-upload-input__item-content\" data-testid={TEST_IDS.mediaBody}>\n <Body type={Typography.BODY_LARGE_BOLD} className=\"np-upload-input__title\">\n {renderButtonTitle()}\n </Body>\n {renderDescription()}\n </div>\n <input\n className=\"np-upload-input__upload-button-input sr-only\"\n type=\"file\"\n id={id}\n {...getAcceptedTypes()}\n {...(multiple && { multiple: true })}\n ref={inputRef}\n disabled={disabled}\n name=\"file-upload\"\n data-testid={TEST_IDS.uploadInput}\n onChange={filesSelected}\n />\n {isDropping && (\n <div\n className={clsx(\n 'np-upload-input__drop-file-overlay',\n 'droppable-card',\n 'droppable-dropping-card',\n 'droppable-card-content',\n )}\n >\n <PlusIcon className=\"m-x-1\" size={24} />\n <div>{formatMessage(MESSAGES.dropFile)}</div>\n </div>\n )}\n </label>\n );\n },\n);\n\nUploadButton.displayName = 'UploadButton';\n\nexport default UploadButton;\n"],"names":["TEST_IDS","onDragOver","event","preventDefault","DEFAULT_FILE_INPUT_ID","UploadButton","forwardRef","disabled","withEntries","multiple","description","fileTypes","imageFileTypes","sizeLimit","DEFAULT_SIZE_LIMIT","maxFiles","onChange","id","uploadButtonTitle","ref","formatMessage","useIntl","inputRef","useRef","useImperativeHandle","current","Error","isDropping","setIsDropping","useState","dragCounter","reset","onDragLeave","onDragEnter","onDrop","dataTransfer","files","filesSelected","target","value","getFileTypesDescription","getAllowedFileTypes","Array","isArray","join","getDescription","fileTypesDescription","derivedFileDescription","MESSAGES","allFileTypes","instructions","size","Math","round","getAcceptedTypes","areAllFilesAllowed","accept","renderDescription","_jsxs","Body","className","children","_Fragment","_jsx","maximumFiles","renderButtonTitle","uploadFiles","uploadFile","clsx","htmlFor","UploadIcon","mediaBody","type","Typography","BODY_LARGE_BOLD","name","uploadInput","PlusIcon","dropFile","displayName"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@transferwise/components",
|
|
3
|
-
"version": "46.
|
|
3
|
+
"version": "46.101.0",
|
|
4
4
|
"description": "Neptune React components",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -84,8 +84,8 @@
|
|
|
84
84
|
"storybook-addon-tag-badges": "^2.0.1",
|
|
85
85
|
"storybook-addon-test-codegen": "^2.0.1",
|
|
86
86
|
"@transferwise/less-config": "3.1.2",
|
|
87
|
-
"@wise/components-theming": "1.6.4",
|
|
88
87
|
"@transferwise/neptune-css": "14.24.5",
|
|
88
|
+
"@wise/components-theming": "1.6.4",
|
|
89
89
|
"@wise/wds-configs": "0.0.0"
|
|
90
90
|
},
|
|
91
91
|
"peerDependencies": {
|
package/src/i18n/en.json
CHANGED
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"neptune.Upload.csFailureText": "Upload failed. Please, try again",
|
|
46
46
|
"neptune.Upload.csSuccessText": "Upload complete!",
|
|
47
47
|
"neptune.Upload.csTooLargeMessage": "Please provide a file smaller than {maxSize}MB",
|
|
48
|
+
"neptune.Upload.csTooLargeNoLimitMessage": "Please provide a smaller file",
|
|
48
49
|
"neptune.Upload.csWrongTypeMessage": "File type not supported. Please try again with a different file",
|
|
49
50
|
"neptune.Upload.psButtonText": "Cancel",
|
|
50
51
|
"neptune.Upload.psProcessingText": "Uploading...",
|
|
@@ -52,6 +53,7 @@
|
|
|
52
53
|
"neptune.Upload.usButtonText": "Or select a file",
|
|
53
54
|
"neptune.Upload.usDropMessage": "Drop file to start upload",
|
|
54
55
|
"neptune.Upload.usPlaceholder": "Drag and drop a file less than {maxSize}MB",
|
|
56
|
+
"neptune.Upload.usPlaceholderNoLimit": "Drag and drop a file",
|
|
55
57
|
"neptune.UploadButton.allFileTypes": "All file types",
|
|
56
58
|
"neptune.UploadButton.dropFiles": "Drop file to start upload",
|
|
57
59
|
"neptune.UploadButton.instructions": "{fileTypes}, less than {size}MB",
|
|
@@ -17,6 +17,10 @@ export default defineMessages({
|
|
|
17
17
|
id: 'neptune.Upload.csTooLargeMessage',
|
|
18
18
|
defaultMessage: 'Please provide a file smaller than {maxSize}MB',
|
|
19
19
|
},
|
|
20
|
+
csTooLargeNoLimitMessage: {
|
|
21
|
+
id: 'neptune.Upload.csTooLargeNoLimitMessage',
|
|
22
|
+
defaultMessage: 'Please provide a smaller file',
|
|
23
|
+
},
|
|
20
24
|
csWrongTypeMessage: {
|
|
21
25
|
id: 'neptune.Upload.csWrongTypeMessage',
|
|
22
26
|
defaultMessage: 'File type not supported. Please try again with a different file',
|
|
@@ -41,6 +45,10 @@ export default defineMessages({
|
|
|
41
45
|
id: 'neptune.Upload.usPlaceholder',
|
|
42
46
|
defaultMessage: 'Drag and drop a file less than {maxSize}MB',
|
|
43
47
|
},
|
|
48
|
+
usPlaceholderNoLimit: {
|
|
49
|
+
id: 'neptune.Upload.usPlaceholderNoLimit',
|
|
50
|
+
defaultMessage: 'Drag and drop a file',
|
|
51
|
+
},
|
|
44
52
|
retry: {
|
|
45
53
|
id: 'neptune.Upload.retry',
|
|
46
54
|
defaultMessage: 'Retry',
|
|
@@ -355,4 +355,10 @@ describe('Upload Component', () => {
|
|
|
355
355
|
expect(container.querySelector('.droppable-processing')).not.toBeInTheDocument();
|
|
356
356
|
expect(props.onStart).not.toHaveBeenCalled();
|
|
357
357
|
});
|
|
358
|
+
|
|
359
|
+
test('should remove max size limit, when maxSize is the `null`', async () => {
|
|
360
|
+
render(<Upload {...props} usPlaceholder={undefined} maxSize={null} />);
|
|
361
|
+
expect(await screen.findByText(/Drag and drop a file/i)).toBeInTheDocument();
|
|
362
|
+
expect(screen.queryByText(/less than/i)).not.toBeInTheDocument();
|
|
363
|
+
});
|
|
358
364
|
});
|
|
@@ -3,18 +3,134 @@ import { fn } from 'storybook/test';
|
|
|
3
3
|
|
|
4
4
|
import Upload from '.';
|
|
5
5
|
import { MAX_SIZE_DEFAULT } from './Upload';
|
|
6
|
-
import { Field } from '../field/Field';
|
|
7
6
|
|
|
8
7
|
const meta = {
|
|
9
8
|
component: Upload,
|
|
10
9
|
title: 'Forms/Upload',
|
|
11
|
-
|
|
10
|
+
args: {
|
|
11
|
+
// Set all props to undefined so Storybook can auto-detect them
|
|
12
|
+
animationDelay: undefined,
|
|
13
|
+
csButtonText: undefined,
|
|
14
|
+
csFailureText: undefined,
|
|
15
|
+
csSuccessText: undefined,
|
|
16
|
+
csTooLargeMessage: undefined,
|
|
17
|
+
csWrongTypeMessage: undefined,
|
|
18
|
+
httpOptions: undefined,
|
|
19
|
+
fetcher: undefined,
|
|
20
|
+
maxSize: undefined,
|
|
21
|
+
psButtonText: undefined,
|
|
22
|
+
psButtonDisabled: undefined,
|
|
23
|
+
psProcessingText: undefined,
|
|
24
|
+
size: undefined,
|
|
25
|
+
usAccept: undefined,
|
|
26
|
+
usButtonText: undefined,
|
|
27
|
+
usButtonRetryText: undefined,
|
|
28
|
+
usDisabled: undefined,
|
|
29
|
+
usDropMessage: undefined,
|
|
30
|
+
usHelpImage: undefined,
|
|
31
|
+
usLabel: undefined,
|
|
32
|
+
usPlaceholder: undefined,
|
|
33
|
+
errorIconLabel: undefined,
|
|
34
|
+
onCancel: undefined,
|
|
35
|
+
onFailure: undefined,
|
|
36
|
+
onStart: undefined,
|
|
37
|
+
onSuccess: undefined,
|
|
38
|
+
uploadStep: undefined,
|
|
39
|
+
},
|
|
12
40
|
argTypes: {
|
|
13
41
|
maxSize: {
|
|
14
42
|
control: {
|
|
15
43
|
type: 'number',
|
|
16
44
|
min: 0,
|
|
17
45
|
},
|
|
46
|
+
description:
|
|
47
|
+
'Filesize expressed in Bytes.<br />If set to `null`, no size limit will be applied.',
|
|
48
|
+
table: {
|
|
49
|
+
type: {
|
|
50
|
+
summary: 'number | null',
|
|
51
|
+
},
|
|
52
|
+
defaultValue: {
|
|
53
|
+
summary: MAX_SIZE_DEFAULT.toString(),
|
|
54
|
+
detail: '5 MB',
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
fetcher: {
|
|
59
|
+
description:
|
|
60
|
+
'You can provide a fetcher function with the same interface as the global fetch function, which is used by default.',
|
|
61
|
+
table: {
|
|
62
|
+
type: {
|
|
63
|
+
summary: 'PostDataFetcher',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
control: false,
|
|
67
|
+
},
|
|
68
|
+
usAccept: {
|
|
69
|
+
description:
|
|
70
|
+
'You can provide multiple rules separated by comma, e.g.: "application/pdf,image/*".\nUsing "*" will allow every file type to be uploaded.',
|
|
71
|
+
},
|
|
72
|
+
errorIconLabel: {
|
|
73
|
+
description:
|
|
74
|
+
"Override for the InlineAlert icon's default, accessible name announced by the screen readers",
|
|
75
|
+
},
|
|
76
|
+
usHelpImage: {
|
|
77
|
+
control: false,
|
|
78
|
+
table: {
|
|
79
|
+
type: {
|
|
80
|
+
summary: 'ReactNode',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
httpOptions: {
|
|
85
|
+
table: {
|
|
86
|
+
type: {
|
|
87
|
+
summary:
|
|
88
|
+
'PostDataHTTPOptions & { fileInputName?: string; data?: Record<string, string | Blob>; }',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
size: {
|
|
93
|
+
table: {
|
|
94
|
+
type: {
|
|
95
|
+
summary: `Size.SMALL | Size.MEDIUM | Size.LARGE`,
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
uploadStep: {
|
|
100
|
+
description: '**@deprecated** Only a single variant exists, please remove this prop.',
|
|
101
|
+
table: {
|
|
102
|
+
type: {
|
|
103
|
+
summary: '"uploadImageStep"',
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
onCancel: {
|
|
108
|
+
table: {
|
|
109
|
+
type: {
|
|
110
|
+
summary: '() => void',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
onFailure: {
|
|
115
|
+
table: {
|
|
116
|
+
type: {
|
|
117
|
+
summary: '(error: unknown) => void',
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
onStart: {
|
|
122
|
+
table: {
|
|
123
|
+
type: {
|
|
124
|
+
summary: '(file: File) => void',
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
onSuccess: {
|
|
129
|
+
table: {
|
|
130
|
+
type: {
|
|
131
|
+
summary: '(response: string | Response, fileName: string) => void',
|
|
132
|
+
},
|
|
133
|
+
},
|
|
18
134
|
},
|
|
19
135
|
},
|
|
20
136
|
} satisfies Meta<typeof Upload>;
|
|
@@ -24,7 +140,6 @@ type Story = StoryObj<typeof meta>;
|
|
|
24
140
|
|
|
25
141
|
export const Basic: Story = {
|
|
26
142
|
args: {
|
|
27
|
-
maxSize: MAX_SIZE_DEFAULT,
|
|
28
143
|
usAccept: 'image/*',
|
|
29
144
|
usLabel: 'Front of your ID document',
|
|
30
145
|
usDisabled: false,
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import type { Meta
|
|
2
|
-
import { fn } from 'storybook/test';
|
|
1
|
+
import type { Meta } from '@storybook/react-webpack5';
|
|
3
2
|
|
|
4
3
|
import Upload from '.';
|
|
5
|
-
import { MAX_SIZE_DEFAULT } from './Upload';
|
|
6
4
|
import { Field } from '../field/Field';
|
|
7
5
|
|
|
8
6
|
const meta = {
|
|
@@ -59,6 +57,10 @@ export const MaxSizes = () => {
|
|
|
59
57
|
<Upload usLabel="Pick a file, any file" maxSize={maxSize} />
|
|
60
58
|
</Field>
|
|
61
59
|
))}
|
|
60
|
+
|
|
61
|
+
<Field label="Max size: null (no limit)">
|
|
62
|
+
<Upload usLabel="Pick a file, any file" maxSize={null} />
|
|
63
|
+
</Field>
|
|
62
64
|
</div>
|
|
63
65
|
<div style={{ flex: 1 }}>
|
|
64
66
|
{decimalSizes.map((maxSize) => (
|
package/src/upload/Upload.tsx
CHANGED
|
@@ -10,7 +10,6 @@ import messages from './Upload.messages';
|
|
|
10
10
|
import { UploadImageStep, ProcessingStep, CompleteStep } from './steps';
|
|
11
11
|
import { postData, asyncFileRead, isSizeValid, isTypeValid, getFileType } from './utils';
|
|
12
12
|
import { PostDataFetcher, PostDataHTTPOptions, ResponseError } from './utils/postData/postData';
|
|
13
|
-
import { ProcessIndicatorStatus } from '../processIndicator';
|
|
14
13
|
|
|
15
14
|
export const MAX_SIZE_DEFAULT = 5000000;
|
|
16
15
|
|
|
@@ -31,10 +30,14 @@ export interface UploadProps extends WrappedComponentProps {
|
|
|
31
30
|
};
|
|
32
31
|
/**
|
|
33
32
|
* You can provide a fetcher function with the same interface as the global fetch function, which is used by default.
|
|
34
|
-
* function fetcher(input: RequestInfo, init?: RequestInit): Promise<Response
|
|
33
|
+
* `function fetcher(input: RequestInfo, init?: RequestInit): Promise<Response>`
|
|
35
34
|
*/
|
|
36
35
|
fetcher?: PostDataFetcher;
|
|
37
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Filesize expressed in B.<br />If set to `null`, no size limit will be applied.
|
|
38
|
+
* @default 5000000 (5 MB)
|
|
39
|
+
*/
|
|
40
|
+
maxSize?: number | null;
|
|
38
41
|
psButtonText?: string;
|
|
39
42
|
psButtonDisabled?: boolean;
|
|
40
43
|
psProcessingText?: string;
|
|
@@ -114,9 +117,9 @@ export class Upload extends Component<UploadProps, UploadState> {
|
|
|
114
117
|
case 413:
|
|
115
118
|
return (
|
|
116
119
|
csTooLargeMessage ||
|
|
117
|
-
|
|
118
|
-
maxSize: roundFileSize(maxSize)
|
|
119
|
-
|
|
120
|
+
(typeof maxSize === 'number'
|
|
121
|
+
? intl.formatMessage(messages.csTooLargeMessage, { maxSize: roundFileSize(maxSize) })
|
|
122
|
+
: intl.formatMessage(messages.csTooLargeNoLimitMessage))
|
|
120
123
|
);
|
|
121
124
|
case 415:
|
|
122
125
|
return csWrongTypeMessage || intl.formatMessage(messages.csWrongTypeMessage);
|
|
@@ -279,7 +282,7 @@ export class Upload extends Component<UploadProps, UploadState> {
|
|
|
279
282
|
return false;
|
|
280
283
|
}
|
|
281
284
|
|
|
282
|
-
if (!isSizeValid(file, maxSize)) {
|
|
285
|
+
if (typeof maxSize === 'number' && !isSizeValid(file, maxSize)) {
|
|
283
286
|
this.asyncResponse(
|
|
284
287
|
new ResponseError(
|
|
285
288
|
new Response(null, {
|
|
@@ -344,6 +347,18 @@ export class Upload extends Component<UploadProps, UploadState> {
|
|
|
344
347
|
uploadedImage,
|
|
345
348
|
} = this.state;
|
|
346
349
|
|
|
350
|
+
const placeholder = ((): string => {
|
|
351
|
+
if (usPlaceholder) {
|
|
352
|
+
return usPlaceholder;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (typeof maxSize === 'number') {
|
|
356
|
+
return intl.formatMessage(messages.usPlaceholder, { maxSize: roundFileSize(maxSize) });
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return intl.formatMessage(messages.usPlaceholderNoLimit);
|
|
360
|
+
})();
|
|
361
|
+
|
|
347
362
|
return (
|
|
348
363
|
<div
|
|
349
364
|
className={clsx('droppable-area', {
|
|
@@ -370,10 +385,7 @@ export class Upload extends Component<UploadProps, UploadState> {
|
|
|
370
385
|
usDisabled={usDisabled}
|
|
371
386
|
usHelpImage={usHelpImage}
|
|
372
387
|
usLabel={usLabel}
|
|
373
|
-
usPlaceholder={
|
|
374
|
-
usPlaceholder ||
|
|
375
|
-
intl.formatMessage(messages.usPlaceholder, { maxSize: roundFileSize(maxSize) })
|
|
376
|
-
}
|
|
388
|
+
usPlaceholder={placeholder}
|
|
377
389
|
/>
|
|
378
390
|
)}
|
|
379
391
|
|
|
@@ -400,10 +412,7 @@ export class Upload extends Component<UploadProps, UploadState> {
|
|
|
400
412
|
usDisabled={usDisabled}
|
|
401
413
|
usHelpImage={null}
|
|
402
414
|
usLabel={usLabel}
|
|
403
|
-
usPlaceholder={
|
|
404
|
-
usPlaceholder ||
|
|
405
|
-
intl.formatMessage(messages.usPlaceholder, { maxSize: roundFileSize(maxSize) })
|
|
406
|
-
}
|
|
415
|
+
usPlaceholder={placeholder}
|
|
407
416
|
errorMessage={this.getErrorMessage(
|
|
408
417
|
response != null &&
|
|
409
418
|
typeof response === 'object' &&
|
|
@@ -233,6 +233,13 @@ export const WithFileSizeErrorMessage: Story = {
|
|
|
233
233
|
},
|
|
234
234
|
};
|
|
235
235
|
|
|
236
|
+
export const WithNoSizeLimit: Story = {
|
|
237
|
+
args: {
|
|
238
|
+
...props,
|
|
239
|
+
sizeLimit: null,
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
|
|
236
243
|
export const WithCustomUploadButtonTitle: Story = {
|
|
237
244
|
args: {
|
|
238
245
|
...props,
|
|
@@ -91,7 +91,7 @@ export type UploadInputProps = {
|
|
|
91
91
|
maxFilesErrorMessage?: string;
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
* Error message to show when files over
|
|
94
|
+
* Error message to show when files over allowed size limit are uploaded
|
|
95
95
|
*/
|
|
96
96
|
sizeLimitErrorMessage?: string;
|
|
97
97
|
} & Pick<
|
|
@@ -269,7 +269,7 @@ const UploadInput = ({
|
|
|
269
269
|
continue;
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
-
if (!isSizeValid(file, sizeLimit * 1000)) {
|
|
272
|
+
if (typeof sizeLimit === 'number' && !isSizeValid(file, sizeLimit * 1000)) {
|
|
273
273
|
const failureMessage = sizeLimitErrorMessage || formatMessage(MESSAGES.fileIsTooLarge);
|
|
274
274
|
handleFileUploadFailure(file, failureMessage);
|
|
275
275
|
continue;
|
|
@@ -96,6 +96,12 @@ describe('UploadButton', () => {
|
|
|
96
96
|
expect(screen.getByText('All file types, less than 5MB')).toBeInTheDocument();
|
|
97
97
|
});
|
|
98
98
|
|
|
99
|
+
it('should show no file size limit if sizeLimit is set to `null`', () => {
|
|
100
|
+
renderComponent({ ...props, fileTypes: ['*'], sizeLimit: null });
|
|
101
|
+
expect(screen.getByText('All file types')).toBeInTheDocument();
|
|
102
|
+
expect(screen.queryByText(/less than/i)).not.toBeInTheDocument();
|
|
103
|
+
});
|
|
104
|
+
|
|
99
105
|
it('should show custom description if provided', () => {
|
|
100
106
|
const description = 'Test description';
|
|
101
107
|
renderComponent({ ...props, fileTypes: ['*'], description });
|
|
@@ -42,9 +42,11 @@ export type UploadButtonProps = {
|
|
|
42
42
|
fileTypes?: AllowedFileTypes;
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
* Size limit in KBs 1000 KB = 1 MB
|
|
45
|
+
* Size limit in KBs (1000 KB = 1 MB).
|
|
46
|
+
* If set to `null`, no size limit will be applied.
|
|
47
|
+
* @default 5000
|
|
46
48
|
*/
|
|
47
|
-
sizeLimit?: number;
|
|
49
|
+
sizeLimit?: number | null;
|
|
48
50
|
|
|
49
51
|
/**
|
|
50
52
|
* Description for the upload button
|
|
@@ -173,10 +175,14 @@ const UploadButton = forwardRef<HTMLInputElement | null, UploadButtonProps>(
|
|
|
173
175
|
const derivedFileDescription =
|
|
174
176
|
fileTypesDescription === '*' ? formatMessage(MESSAGES.allFileTypes) : fileTypesDescription;
|
|
175
177
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
178
|
+
if (typeof sizeLimit === 'number') {
|
|
179
|
+
return formatMessage(MESSAGES.instructions, {
|
|
180
|
+
fileTypes: derivedFileDescription,
|
|
181
|
+
size: Math.round(sizeLimit / 1000),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return derivedFileDescription;
|
|
180
186
|
}
|
|
181
187
|
|
|
182
188
|
function getAcceptedTypes(): Pick<React.ComponentPropsWithoutRef<'input'>, 'accept'> {
|