diff --git a/src/file-upload/__tests__/file-upload-dropzone.test.tsx b/src/file-upload/__tests__/file-upload-dropzone.test.tsx
index d47abf3c96..8a98763c80 100644
--- a/src/file-upload/__tests__/file-upload-dropzone.test.tsx
+++ b/src/file-upload/__tests__/file-upload-dropzone.test.tsx
@@ -4,6 +4,7 @@ import React from 'react';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { Dropzone, useDropzoneVisible } from '../../../lib/components/file-upload/dropzone';
import selectors from '../../../lib/components/file-upload/dropzone/styles.selectors.js';
+import FileUpload, { FileUploadProps } from '../../../lib/components/file-upload';
const file1 = new File([new Blob(['Test content 1'], { type: 'text/plain' })], 'test-file-1.txt', {
type: 'text/plain',
@@ -14,29 +15,60 @@ const file2 = new File([new Blob(['Test content 2'], { type: 'text/plain' })], '
lastModified: 1590962400000,
});
-function createDragEvent(type: string) {
+function createDragEvent(type: string, files = [file1, file2]) {
const event = new CustomEvent(type, { bubbles: true });
- (event as any).dataTransfer = { types: ['Files'], files: [file1, file2] };
+ (event as any).dataTransfer = {
+ types: ['Files'],
+ files: type === 'drop' ? files : [],
+ items: files.map(() => ({ kind: 'file' })),
+ };
return event;
}
-function TestDropzoneVisible() {
- const isDropzoneVisible = useDropzoneVisible();
+function TestDropzoneVisible({ multiple = false }) {
+ const isDropzoneVisible = useDropzoneVisible(multiple);
return
{isDropzoneVisible ? 'visible' : 'hidden'}
;
}
+const i18nStrings: FileUploadProps.I18nStrings = {
+ uploadButtonText: multiple => (multiple ? 'Choose files' : 'Choose file'),
+ dropzoneText: multiple => (multiple ? 'Drag files to upload' : 'Drag file to upload'),
+ removeFileAriaLabel: fileIndex => `Remove file ${fileIndex + 1}`,
+ errorIconAriaLabel: 'Error',
+ limitShowFewer: 'Show fewer files',
+ limitShowMore: 'Show more files',
+};
+
describe('File upload dropzone', () => {
test('Dropzone becomes visible once global dragover event is received', () => {
render();
expect(screen.getByText('hidden')).toBeDefined();
- fireEvent(document, createDragEvent('dragover'));
+ fireEvent(document, createDragEvent('dragover', [file1]));
expect(screen.getByText('visible')).toBeDefined();
});
- test('Dropzone hides after a delay once global dragleave event is received', async () => {
+ test('Dropzone does not show if multiple files dragged into non-multiple zone', () => {
render();
+ expect(screen.getByText('hidden')).toBeDefined();
+
+ fireEvent(document, createDragEvent('dragover', [file1, file2]));
+
+ expect(screen.getByText('hidden')).toBeDefined();
+ });
+
+ test('Dropzone shows if multiple files dragged into multiple zone', () => {
+ render();
+ expect(screen.getByText('hidden')).toBeDefined();
+
+ fireEvent(document, createDragEvent('dragover', [file1, file2]));
+
+ expect(screen.getByText('visible')).toBeDefined();
+ });
+
+ test('Dropzone hides after a delay once global dragleave event is received', async () => {
+ render();
fireEvent(document, createDragEvent('dragover'));
@@ -50,7 +82,7 @@ describe('File upload dropzone', () => {
});
test('Dropzone hides after a delay once global drop event is received', async () => {
- render();
+ render();
fireEvent(document, createDragEvent('dragover'));
@@ -63,6 +95,12 @@ describe('File upload dropzone', () => {
});
});
+ test('dropzone is rendered in component', () => {
+ render();
+ fireEvent(document, createDragEvent('dragover'));
+ expect(screen.getByText('Drag files to upload')).toBeDefined();
+ });
+
test('dropzone renders provided children', () => {
render(Drop files here);
expect(screen.findByText('Drop files here')).toBeDefined();
diff --git a/src/file-upload/dropzone/index.tsx b/src/file-upload/dropzone/index.tsx
index c5919b8fa5..b49ada808a 100644
--- a/src/file-upload/dropzone/index.tsx
+++ b/src/file-upload/dropzone/index.tsx
@@ -11,7 +11,7 @@ interface DropzoneProps {
children: React.ReactNode;
}
-export function useDropzoneVisible() {
+export function useDropzoneVisible(multiple: boolean) {
const [isDropzoneVisible, setDropzoneVisible] = useState(false);
// Registering global drag events listeners.
@@ -23,7 +23,13 @@ export function useDropzoneVisible() {
const onDocumentDragOver = (event: DragEvent) => {
event.preventDefault();
- if (event.dataTransfer?.types?.indexOf('Files') !== -1) {
+ let files = 0;
+ for (let item = 0; item < (event.dataTransfer?.items.length || 0); item++) {
+ if (event.dataTransfer?.items[item].kind === 'file') {
+ files++;
+ }
+ }
+ if (files > 0 && (multiple || files === 1)) {
setDropzoneVisible(true);
dragTimer && clearTimeout(dragTimer);
}
@@ -53,7 +59,7 @@ export function useDropzoneVisible() {
document.removeEventListener('dragleave', onDocumentDragLeave);
document.removeEventListener('drop', onDocumentDrop);
};
- }, []);
+ }, [multiple]);
return isDropzoneVisible;
}
@@ -63,9 +69,9 @@ export function Dropzone({ onChange, children }: DropzoneProps) {
const onDragOver = (event: React.DragEvent) => {
event.preventDefault();
- setDropzoneHovered(true);
if (event.dataTransfer) {
+ setDropzoneHovered(true);
event.dataTransfer.dropEffect = 'copy';
}
};
diff --git a/src/file-upload/internal.tsx b/src/file-upload/internal.tsx
index 5009bd742c..627b160412 100644
--- a/src/file-upload/internal.tsx
+++ b/src/file-upload/internal.tsx
@@ -80,7 +80,7 @@ function InternalFileUpload(
}
};
- const isDropzoneVisible = useDropzoneVisible();
+ const isDropzoneVisible = useDropzoneVisible(multiple);
const formFieldContext = useFormFieldContext(restProps);
const ariaDescribedBy = joinStrings(