-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DropZone: Convert to TypeScript #43962
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 ( | ||
* <div> | ||
* { hasDropped ? 'Dropped!' : 'Drop something here' } | ||
* <DropZone | ||
* onFilesDrop={ () => setHasDropped( true ) } | ||
* onHTMLDrop={ () => setHasDropped( true ) } | ||
* onDrop={ () => setHasDropped( true ) } | ||
* /> | ||
* </div> | ||
* ); | ||
* } | ||
* ``` | ||
*/ | ||
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 ( | ||
<div ref={ ref } className={ classes }> | ||
<div { ...restProps } ref={ ref } className={ classes }> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
{ disableMotion ? ( | ||
children | ||
) : ( | ||
|
@@ -158,3 +191,5 @@ export default function DropZoneComponent( { | |
</div> | ||
); | ||
} | ||
|
||
export default DropZoneComponent; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,11 @@ | |
*/ | ||
import deprecated from '@wordpress/deprecated'; | ||
|
||
export default function DropZoneProvider( { children } ) { | ||
export default function DropZoneProvider( { | ||
children, | ||
}: { | ||
children: React.ReactNode; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not going to extract this to the types.ts file because this is deprecated. |
||
} ) { | ||
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.', | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 ( | ||
<div style={ { background: 'lightgray', padding: 16 } }> | ||
Drop something here | ||
<DropZone { ...props } /> | ||
</div> | ||
); | ||
}; | ||
|
||
export const Default = Template.bind( {} ); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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. | ||
Comment on lines
+36
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
* | ||
* @return {import('react').RefCallback<HTMLElement>} Ref callback to be passed to the drop zone element. | ||
*/ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this component be polymorphic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be potentially, but not in the current form because the
div
used in the code is a raw div element and not a polymorphic one (likeView
orstyled.div
).