Skip to content

Commit b40802d

Browse files
authored
Fix: dropzone doesn't receive drop event (#5415)
* Fix: dropzone doesn't get drop events * Improve * Changelog * Add test
1 parent 1f5e557 commit b40802d

File tree

3 files changed

+38
-6
lines changed

3 files changed

+38
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/
121121
- Fixed math parsing that could cause Web Chat to hang when processing certain LaTeX expressions, in PR [#5377](https://github.com/microsoft/BotFramework-WebChat/pull/5377), by [@OEvgeny](https://github.com/OEvgeny)
122122
- Fixed long math formula should be scrollable, in PR [#5380](https://github.com/microsoft/BotFramework-WebChat/pull/5380), by [@compulim](https://github.com/compulim)
123123
- Fixed [#4948](https://github.com/microsoft/BotFramework-WebChat/issues/4948). Microphone should stop after initial silence, in PR [#5385](https://github.com/microsoft/BotFramework-WebChat/pull/5385)
124-
- Fixed [#5390](https://github.com/microsoft/BotFramework-WebChat/issues/5390). Fixed drop zone remaining visible when file is dropped outside of the zone, in PR [#5394](https://github.com/microsoft/BotFramework-WebChat/pull/5394), by [@OEvgeny](https://github.com/OEvgeny)
124+
- Fixed [#5390](https://github.com/microsoft/BotFramework-WebChat/issues/5390). Fixed drop zone remaining visible when file is dropped outside of the zone, in PR [#5394](https://github.com/microsoft/BotFramework-WebChat/pull/5394), in PR [#5415](https://github.com/microsoft/BotFramework-WebChat/pull/5415), by [@OEvgeny](https://github.com/OEvgeny)
125125

126126
# Removed
127127

__tests__/html/fluentTheme/dragAndDrop.upload.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,18 @@
9595
// THEN: Should render the drop zone.
9696
await host.snapshot();
9797

98+
// WHEN: Dragging a file over the document.
99+
const dragOverDocumentEvent = new DragEvent('dragover', {
100+
bubbles: true,
101+
cancelable: true,
102+
dataTransfer
103+
});
104+
105+
document.dispatchEvent(dragOverDocumentEvent);
106+
107+
// THEN: The default browser behavior should be prevented.
108+
await pageConditions.became('DragOver event preventDefault is called', () => dragOverDocumentEvent.defaultPrevented, 1000);
109+
98110
// WHEN: Dropping out of the drop zone.
99111
const dropEvent1 = new DragEvent('drop', {
100112
bubbles: true,

packages/fluent-theme/src/components/dropZone/DropZone.tsx

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import { hooks } from 'botframework-webchat-component';
22
import cx from 'classnames';
3-
import React, { memo, useCallback, useEffect, useRef, useState, type DragEventHandler } from 'react';
3+
import React, {
4+
memo,
5+
useCallback,
6+
useEffect,
7+
useRef,
8+
useState,
9+
type DragEvent as ReactDragEvent,
10+
type DragEventHandler
11+
} from 'react';
412
import { useRefFrom } from 'use-ref-from';
513

614
import { AddDocumentIcon } from '../../icons';
@@ -10,8 +18,14 @@ import { useStyles } from '../../styles';
1018

1119
const { useLocalizer } = hooks;
1220

13-
const handleDragOver: DragEventHandler<HTMLDivElement> = event => {
14-
// This is for preventing the browser from opening the dropped file in a new tab.
21+
const handleDragOver = (event: ReactDragEvent<unknown> | DragEvent) => {
22+
// Prevent default dragover behavior to enable drop event triggering.
23+
// Browsers require this to fire subsequent drop events - without it,
24+
// they would handle the drop directly (e.g., open files in new tabs).
25+
// This is needed regardless of whether we prevent default drop behavior,
26+
// as it ensures our dropzone receives the drop event first. If we allow
27+
// default drop handling (by not calling preventDefault there), the browser
28+
// will still process the drop after our event handlers complete.
1529
event.preventDefault();
1630
};
1731

@@ -47,6 +61,8 @@ const DropZone = (props: { readonly onFilesAdded: (files: File[]) => void }) =>
4761
let entranceCounter = 0;
4862

4963
const handleDragEnter = (event: DragEvent) => {
64+
document.addEventListener('dragover', handleDragOver);
65+
5066
entranceCounter++;
5167

5268
if (isFilesTransferEvent(event)) {
@@ -63,7 +79,10 @@ const DropZone = (props: { readonly onFilesAdded: (files: File[]) => void }) =>
6379
const handleDragLeave = () => --entranceCounter <= 0 && setDropZoneState(false);
6480

6581
const handleDragEnd = () => {
82+
document.removeEventListener('dragover', handleDragOver);
83+
6684
entranceCounter = 0;
85+
6786
setDropZoneState(false);
6887
};
6988

@@ -73,15 +92,16 @@ const DropZone = (props: { readonly onFilesAdded: (files: File[]) => void }) =>
7392
}
7493
};
7594

95+
document.addEventListener('dragend', handleDragEnd);
7696
document.addEventListener('dragenter', handleDragEnter);
7797
document.addEventListener('dragleave', handleDragLeave);
78-
document.addEventListener('dragend', handleDragEnd);
7998
document.addEventListener('drop', handleDocumentDrop);
8099

81100
return () => {
101+
document.removeEventListener('dragend', handleDragEnd);
82102
document.removeEventListener('dragenter', handleDragEnter);
83103
document.removeEventListener('dragleave', handleDragLeave);
84-
document.removeEventListener('dragend', handleDragEnd);
104+
document.removeEventListener('dragover', handleDragOver);
85105
document.removeEventListener('drop', handleDocumentDrop);
86106
};
87107
}, [setDropZoneState]);

0 commit comments

Comments
 (0)