react-dropzone 14.3.8 → 14.4.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/.nvmrc CHANGED
@@ -1 +1 @@
1
- 20.17.0
1
+ 22
@@ -0,0 +1,28 @@
1
+ {
2
+ "branches": ["master"],
3
+ "plugins": [
4
+ "@semantic-release/commit-analyzer",
5
+ "@semantic-release/release-notes-generator",
6
+ "@semantic-release/changelog",
7
+ [
8
+ "@semantic-release/npm",
9
+ {
10
+ "npmPublish": true,
11
+ "pkgRoot": ".",
12
+ "tarballDir": "dist",
13
+ "provenance": true
14
+ }
15
+ ],
16
+ [
17
+ "@semantic-release/github",
18
+ {
19
+ "assets": [
20
+ {
21
+ "path": "dist/*.tgz",
22
+ "label": "Distribution"
23
+ }
24
+ ]
25
+ }
26
+ ]
27
+ ]
28
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # [14.4.0](https://github.com/react-dropzone/react-dropzone/compare/v14.3.8...v14.4.0) (2026-01-29)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * accept files with empty type during drag events ([eaa8ba5](https://github.com/react-dropzone/react-dropzone/commit/eaa8ba54963480afbba50415b1dd792514fefac1))
7
+ * correct dragLeave filter logic and add dragend test ([273aff4](https://github.com/react-dropzone/react-dropzone/commit/273aff4a151aba05ddd473cbc49dc3db59132f2f))
8
+
9
+
10
+ ### Features
11
+
12
+ * add isDragGlobal state for document-level drag detection ([f0874b0](https://github.com/react-dropzone/react-dropzone/commit/f0874b0ad8e94dbf662b16bc82d0aa2b082ec8ee))
package/dist/es/index.js CHANGED
@@ -103,6 +103,7 @@ Dropzone.propTypes = {
103
103
  * @param {boolean} params.isDragActive Active drag is in progress
104
104
  * @param {boolean} params.isDragAccept Dragged files are accepted
105
105
  * @param {boolean} params.isDragReject Some dragged files are rejected
106
+ * @param {boolean} params.isDragGlobal Files are being dragged anywhere on the document
106
107
  * @param {File[]} params.acceptedFiles Accepted files
107
108
  * @param {FileRejection[]} params.fileRejections Rejected files and why they were rejected
108
109
  */
@@ -339,6 +340,7 @@ export default Dropzone;
339
340
  * @property {boolean} isDragActive Active drag is in progress
340
341
  * @property {boolean} isDragAccept Dragged files are accepted
341
342
  * @property {boolean} isDragReject Some dragged files are rejected
343
+ * @property {boolean} isDragGlobal Files are being dragged anywhere on the document
342
344
  * @property {File[]} acceptedFiles Accepted files
343
345
  * @property {FileRejection[]} fileRejections Rejected files and why they were rejected
344
346
  */
@@ -358,6 +360,7 @@ var initialState = {
358
360
  isDragActive: false,
359
361
  isDragAccept: false,
360
362
  isDragReject: false,
363
+ isDragGlobal: false,
361
364
  acceptedFiles: [],
362
365
  fileRejections: []
363
366
  };
@@ -521,6 +524,7 @@ export function useDropzone() {
521
524
  };
522
525
  }, [inputRef, isFileDialogActive, onFileDialogCancelCb, fsAccessApiWorksRef]);
523
526
  var dragTargetsRef = useRef([]);
527
+ var globalDragTargetsRef = useRef([]);
524
528
 
525
529
  var onDocumentDrop = function onDocumentDrop(event) {
526
530
  if (rootRef.current && rootRef.current.contains(event.target)) {
@@ -544,7 +548,63 @@ export function useDropzone() {
544
548
  document.removeEventListener("drop", onDocumentDrop);
545
549
  }
546
550
  };
547
- }, [rootRef, preventDropOnDocument]); // Auto focus the root when autoFocus is true
551
+ }, [rootRef, preventDropOnDocument]); // Track global drag state for document-level drag events
552
+
553
+ useEffect(function () {
554
+ var onDocumentDragEnter = function onDocumentDragEnter(event) {
555
+ globalDragTargetsRef.current = [].concat(_toConsumableArray(globalDragTargetsRef.current), [event.target]);
556
+
557
+ if (isEvtWithFiles(event)) {
558
+ dispatch({
559
+ isDragGlobal: true,
560
+ type: "setDragGlobal"
561
+ });
562
+ }
563
+ };
564
+
565
+ var onDocumentDragLeave = function onDocumentDragLeave(event) {
566
+ // Only deactivate once we've left all children
567
+ globalDragTargetsRef.current = globalDragTargetsRef.current.filter(function (el) {
568
+ return el !== event.target && el !== null;
569
+ });
570
+
571
+ if (globalDragTargetsRef.current.length > 0) {
572
+ return;
573
+ }
574
+
575
+ dispatch({
576
+ isDragGlobal: false,
577
+ type: "setDragGlobal"
578
+ });
579
+ };
580
+
581
+ var onDocumentDragEnd = function onDocumentDragEnd() {
582
+ globalDragTargetsRef.current = [];
583
+ dispatch({
584
+ isDragGlobal: false,
585
+ type: "setDragGlobal"
586
+ });
587
+ };
588
+
589
+ var onDocumentDropGlobal = function onDocumentDropGlobal() {
590
+ globalDragTargetsRef.current = [];
591
+ dispatch({
592
+ isDragGlobal: false,
593
+ type: "setDragGlobal"
594
+ });
595
+ };
596
+
597
+ document.addEventListener("dragenter", onDocumentDragEnter, false);
598
+ document.addEventListener("dragleave", onDocumentDragLeave, false);
599
+ document.addEventListener("dragend", onDocumentDragEnd, false);
600
+ document.addEventListener("drop", onDocumentDropGlobal, false);
601
+ return function () {
602
+ document.removeEventListener("dragenter", onDocumentDragEnter);
603
+ document.removeEventListener("dragleave", onDocumentDragLeave);
604
+ document.removeEventListener("dragend", onDocumentDragEnd);
605
+ document.removeEventListener("drop", onDocumentDropGlobal);
606
+ };
607
+ }, [rootRef]); // Auto focus the root when autoFocus is true
548
608
 
549
609
  useEffect(function () {
550
610
  if (!disabled && autoFocus && rootRef.current) {
@@ -970,6 +1030,11 @@ function reducer(state, action) {
970
1030
  isDragReject: action.isDragReject
971
1031
  });
972
1032
 
1033
+ case "setDragGlobal":
1034
+ return _objectSpread(_objectSpread({}, state), {}, {
1035
+ isDragGlobal: action.isDragGlobal
1036
+ });
1037
+
973
1038
  case "reset":
974
1039
  return _objectSpread({}, initialState);
975
1040
 
@@ -69,19 +69,43 @@ export var TOO_MANY_FILES_REJECTION = {
69
69
  code: TOO_MANY_FILES,
70
70
  message: "Too many files"
71
71
  };
72
+ /**
73
+ * Check if the given file is a DataTransferItem with an empty type.
74
+ *
75
+ * During drag events, browsers may return DataTransferItem objects instead of File objects.
76
+ * Some browsers (e.g., Chrome) return an empty MIME type for certain file types (like .md files)
77
+ * on DataTransferItem during drag events, even though the type is correctly set during drop.
78
+ *
79
+ * This function detects such cases by checking for:
80
+ * 1. Empty type string
81
+ * 2. Presence of getAsFile method (indicates it's a DataTransferItem, not a File)
82
+ *
83
+ * We accept these during drag to provide proper UI feedback, while maintaining
84
+ * strict validation during drop when real File objects are available.
85
+ *
86
+ * @param {File | DataTransferItem} file
87
+ * @returns {boolean}
88
+ */
89
+
90
+ export function isDataTransferItemWithEmptyType(file) {
91
+ return file.type === "" && typeof file.getAsFile === "function";
92
+ }
72
93
  /**
73
94
  * Check if file is accepted.
74
95
  *
75
96
  * Firefox versions prior to 53 return a bogus MIME type for every file drag,
76
97
  * so dragovers with that MIME type will always be accepted.
77
98
  *
99
+ * Chrome/other browsers may return an empty MIME type for files during drag events,
100
+ * so we accept those as well (we'll validate properly on drop).
101
+ *
78
102
  * @param {File} file
79
103
  * @param {string} accept
80
104
  * @returns
81
105
  */
82
106
 
83
107
  export function fileAccepted(file, accept) {
84
- var isAcceptable = file.type === "application/x-moz-file" || accepts(file, accept);
108
+ var isAcceptable = file.type === "application/x-moz-file" || accepts(file, accept) || isDataTransferItemWithEmptyType(file);
85
109
  return [isAcceptable, isAcceptable ? null : getInvalidTypeRejectionErr(accept)];
86
110
  }
87
111
  export function fileMatchSize(file, minSize, maxSize) {