diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index 1b25ebd6ccac0b..e1168279bd4717 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -31,6 +31,7 @@
- `RadioControl`: Clean up styles to use less custom CSS ([#43868](https://github.com/WordPress/gutenberg/pull/43868)).
- Remove unused `normalizeArrowKey` utility function ([#43640](https://github.com/WordPress/gutenberg/pull/43640/)).
- `SearchControl`: Convert to TypeScript ([#43871](https://github.com/WordPress/gutenberg/pull/43871)).
+- `DropZone`: Convert to TypeScript ([#43962](https://github.com/WordPress/gutenberg/pull/43962)).
- `ToggleGroupControl`: Rename `__experimentalIsIconGroup` prop to `__experimentalIsBorderless` ([#43771](https://github.com/WordPress/gutenberg/pull/43771/)).
- Refactor `FocalPointPicker` to function component ([#39168](https://github.com/WordPress/gutenberg/pull/39168)).
- `Guide`: use `code` instead of `keyCode` for keyboard events ([#43604](https://github.com/WordPress/gutenberg/pull/43604/)).
diff --git a/packages/components/src/drop-zone/README.md b/packages/components/src/drop-zone/README.md
index d267e547b4086e..b06d278c5d1e5d 100644
--- a/packages/components/src/drop-zone/README.md
+++ b/packages/components/src/drop-zone/README.md
@@ -1,6 +1,6 @@
# DropZone
-`DropZone` is a Component creating a drop zone area taking the full size of its parent element. It supports dropping files, HTML content or any other HTML drop event.
+`DropZone` is a component creating a drop zone area taking the full size of its parent element. It supports dropping files, HTML content or any other HTML drop event.
## Usage
@@ -30,7 +30,7 @@ The component accepts the following props:
### className
-A CSS `class` to be _appended_ after the default `components-drop-zone` class.
+A CSS `class` to give to the wrapper element.
- Type: `String`
- Default: `undefined`
@@ -52,7 +52,7 @@ The function is called when dropping a file into the `DropZone`. It receives an
### onHTMLDrop
-The function is called when dropping a file into the `DropZone`. It receives the HTML being dropped as an argument.
+The function is called when dropping HTML into the `DropZone`. It receives the HTML being dropped as an argument.
- Type: `Function`
- Required: No
diff --git a/packages/components/src/drop-zone/index.js b/packages/components/src/drop-zone/index.tsx
similarity index 65%
rename from packages/components/src/drop-zone/index.js
rename to packages/components/src/drop-zone/index.tsx
index 53faa01bb1adea..f7f5f78d6901cf 100644
--- a/packages/components/src/drop-zone/index.js
+++ b/packages/components/src/drop-zone/index.tsx
@@ -22,21 +22,51 @@ import {
__unstableMotion as motion,
__unstableAnimatePresence as AnimatePresence,
} from '../animation';
+import type { DropType, DropZoneProps } from './types';
+import type { WordPressComponentProps } from '../ui/context';
-export default function DropZoneComponent( {
+/**
+ * `DropZone` is a component creating a drop zone area taking the full size of its parent element. It supports dropping files, HTML content or any other HTML drop event.
+ *
+ * ```jsx
+ * import { DropZone } from '@wordpress/components';
+ * import { useState } from '@wordpress/element';
+ *
+ * const MyDropZone = () => {
+ * const [ hasDropped, setHasDropped ] = useState( false );
+ *
+ * return (
+ *
+ * { hasDropped ? 'Dropped!' : 'Drop something here' }
+ * setHasDropped( true ) }
+ * onHTMLDrop={ () => setHasDropped( true ) }
+ * onDrop={ () => setHasDropped( true ) }
+ * />
+ *
+ * );
+ * }
+ * ```
+ */
+export function DropZoneComponent( {
className,
label,
onFilesDrop,
onHTMLDrop,
onDrop,
-} ) {
- const [ isDraggingOverDocument, setIsDraggingOverDocument ] = useState();
- const [ isDraggingOverElement, setIsDraggingOverElement ] = useState();
- const [ type, setType ] = useState();
+ ...restProps
+}: WordPressComponentProps< DropZoneProps, 'div', false > ) {
+ const [ isDraggingOverDocument, setIsDraggingOverDocument ] =
+ useState< boolean >();
+ const [ isDraggingOverElement, setIsDraggingOverElement ] =
+ useState< boolean >();
+ const [ type, setType ] = useState< DropType >();
const ref = useDropZone( {
onDrop( event ) {
- const files = getFilesFromDataTransfer( event.dataTransfer );
- const html = event.dataTransfer.getData( 'text/html' );
+ const files = event.dataTransfer
+ ? getFilesFromDataTransfer( event.dataTransfer )
+ : [];
+ const html = event.dataTransfer?.getData( 'text/html' );
/**
* From Windows Chrome 96, the `event.dataTransfer` returns both file object and HTML.
@@ -53,19 +83,22 @@ export default function DropZoneComponent( {
onDragStart( event ) {
setIsDraggingOverDocument( true );
- let _type = 'default';
+ let _type: DropType = 'default';
/**
* From Windows Chrome 96, the `event.dataTransfer` returns both file object and HTML.
* The order of the checks is important to recognise the HTML drop.
*/
- if ( event.dataTransfer.types.includes( 'text/html' ) ) {
+ if ( event.dataTransfer?.types.includes( 'text/html' ) ) {
_type = 'html';
} else if (
// Check for the types because sometimes the files themselves
// are only available on drop.
- event.dataTransfer.types.includes( 'Files' ) ||
- getFilesFromDataTransfer( event.dataTransfer ).length > 0
+ event.dataTransfer?.types.includes( 'Files' ) ||
+ ( event.dataTransfer
+ ? getFilesFromDataTransfer( event.dataTransfer )
+ : []
+ ).length > 0
) {
_type = 'file';
}
@@ -74,7 +107,7 @@ export default function DropZoneComponent( {
},
onDragEnd() {
setIsDraggingOverDocument( false );
- setType();
+ setType( undefined );
},
onDragEnter() {
setIsDraggingOverElement( true );
@@ -149,7 +182,7 @@ export default function DropZoneComponent( {
} );
return (
-
+
{ disableMotion ? (
children
) : (
@@ -158,3 +191,5 @@ export default function DropZoneComponent( {
);
}
+
+export default DropZoneComponent;
diff --git a/packages/components/src/drop-zone/provider.js b/packages/components/src/drop-zone/provider.ts
similarity index 76%
rename from packages/components/src/drop-zone/provider.js
rename to packages/components/src/drop-zone/provider.ts
index e9924489315f76..97109d845434b6 100644
--- a/packages/components/src/drop-zone/provider.js
+++ b/packages/components/src/drop-zone/provider.ts
@@ -3,7 +3,11 @@
*/
import deprecated from '@wordpress/deprecated';
-export default function DropZoneProvider( { children } ) {
+export default function DropZoneProvider( {
+ children,
+}: {
+ children: React.ReactNode;
+} ) {
deprecated( 'wp.components.DropZoneProvider', {
since: '5.8',
hint: 'wp.component.DropZone no longer needs a provider. wp.components.DropZoneProvider is safe to remove from your code.',
diff --git a/packages/components/src/drop-zone/stories/index.tsx b/packages/components/src/drop-zone/stories/index.tsx
new file mode 100644
index 00000000000000..de94c98e4be031
--- /dev/null
+++ b/packages/components/src/drop-zone/stories/index.tsx
@@ -0,0 +1,30 @@
+/**
+ * External dependencies
+ */
+import type { ComponentMeta, ComponentStory } from '@storybook/react';
+/**
+ * Internal dependencies
+ */
+import DropZone from '..';
+
+const meta: ComponentMeta< typeof DropZone > = {
+ component: DropZone,
+ title: 'Components/DropZone',
+ parameters: {
+ actions: { argTypesRegex: '^on.*' },
+ controls: { expanded: true },
+ docs: { source: { state: 'open' } },
+ },
+};
+export default meta;
+
+const Template: ComponentStory< typeof DropZone > = ( props ) => {
+ return (
+
+ Drop something here
+
+
+ );
+};
+
+export const Default = Template.bind( {} );
diff --git a/packages/components/src/drop-zone/types.ts b/packages/components/src/drop-zone/types.ts
new file mode 100644
index 00000000000000..3982889a4f3eac
--- /dev/null
+++ b/packages/components/src/drop-zone/types.ts
@@ -0,0 +1,29 @@
+export type DropType = 'file' | 'html' | 'default';
+
+export type DropZoneProps = {
+ /**
+ * A CSS `class` to give to the wrapper element.
+ */
+ className?: string;
+ /**
+ * A string to be shown within the drop zone area.
+ *
+ * @default `__( 'Drop files to upload' )`
+ */
+ label?: string;
+ /**
+ * The function is generic drop handler called if the `onFilesDrop` or `onHTMLDrop` are not called.
+ * It receives the drop `event` object as an argument.
+ */
+ onDrop?: ( event: DragEvent ) => void;
+ /**
+ * The function is called when dropping a file into the `DropZone`.
+ * It receives an array of dropped files as an argument.
+ */
+ onFilesDrop?: ( files: File[] ) => void;
+ /**
+ * The function is called when dropping HTML into the `DropZone`.
+ * It receives the HTML being dropped as an argument.
+ */
+ onHTMLDrop?: ( html: string ) => void;
+};
diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json
index a896453cb3a56f..451f607ea0b8e9 100644
--- a/packages/components/tsconfig.json
+++ b/packages/components/tsconfig.json
@@ -48,7 +48,6 @@
"src/custom-gradient-picker",
"src/custom-select-control",
"src/dimension-control",
- "src/drop-zone",
"src/duotone-picker",
"src/focal-point-picker",
"src/font-size-picker",
diff --git a/packages/compose/src/hooks/use-drop-zone/index.js b/packages/compose/src/hooks/use-drop-zone/index.js
index 73f1e9eb03b35c..1d30c92a16ff3c 100644
--- a/packages/compose/src/hooks/use-drop-zone/index.js
+++ b/packages/compose/src/hooks/use-drop-zone/index.js
@@ -33,14 +33,14 @@ function useFreshRef( value ) {
/**
* A hook to facilitate drag and drop handling.
*
- * @param {Object} props Named parameters.
- * @param {boolean} props.isDisabled Whether or not to disable the drop zone.
- * @param {(e: DragEvent) => void} props.onDragStart Called when dragging has started.
- * @param {(e: DragEvent) => void} props.onDragEnter Called when the zone is entered.
- * @param {(e: DragEvent) => void} props.onDragOver Called when the zone is moved within.
- * @param {(e: DragEvent) => void} props.onDragLeave Called when the zone is left.
- * @param {(e: MouseEvent) => void} props.onDragEnd Called when dragging has ended.
- * @param {(e: DragEvent) => void} props.onDrop Called when dropping in the zone.
+ * @param {Object} props Named parameters.
+ * @param {boolean} [props.isDisabled] Whether or not to disable the drop zone.
+ * @param {(e: DragEvent) => void} [props.onDragStart] Called when dragging has started.
+ * @param {(e: DragEvent) => void} [props.onDragEnter] Called when the zone is entered.
+ * @param {(e: DragEvent) => void} [props.onDragOver] Called when the zone is moved within.
+ * @param {(e: DragEvent) => void} [props.onDragLeave] Called when the zone is left.
+ * @param {(e: MouseEvent) => void} [props.onDragEnd] Called when dragging has ended.
+ * @param {(e: DragEvent) => void} [props.onDrop] Called when dropping in the zone.
*
* @return {import('react').RefCallback
} Ref callback to be passed to the drop zone element.
*/