@gechiui/components
Version:
UI components for GeChiUI.
154 lines (140 loc) • 3.54 kB
JavaScript
/**
* External dependencies
*/
import classnames from 'classnames';
import { includes } from 'lodash';
/**
* GeChiUI dependencies
*/
import { __ } from '@gechiui/i18n';
import { useState } from '@gechiui/element';
import { upload, Icon } from '@gechiui/icons';
import { getFilesFromDataTransfer } from '@gechiui/dom';
import {
__experimentalUseDropZone as useDropZone,
useReducedMotion,
} from '@gechiui/compose';
/**
* Internal dependencies
*/
import {
__unstableMotion as motion,
__unstableAnimatePresence as AnimatePresence,
} from '../animation';
export default function DropZoneComponent( {
className,
label,
onFilesDrop,
onHTMLDrop,
onDrop,
} ) {
const [ isDraggingOverDocument, setIsDraggingOverDocument ] = useState();
const [ isDraggingOverElement, setIsDraggingOverElement ] = useState();
const [ type, setType ] = useState();
const ref = useDropZone( {
onDrop( event ) {
const files = getFilesFromDataTransfer( event.dataTransfer );
const html = event.dataTransfer.getData( 'text/html' );
if ( files.length && onFilesDrop ) {
onFilesDrop( files );
} else if ( html && onHTMLDrop ) {
onHTMLDrop( html );
} else if ( onDrop ) {
onDrop( event );
}
},
onDragStart( event ) {
setIsDraggingOverDocument( true );
let _type = 'default';
if (
// Check for the types because sometimes the files themselves
// are only available on drop.
includes( event.dataTransfer.types, 'Files' ) ||
getFilesFromDataTransfer( event.dataTransfer ).length > 0
) {
_type = 'file';
} else if ( includes( event.dataTransfer.types, 'text/html' ) ) {
_type = 'html';
}
setType( _type );
},
onDragEnd() {
setIsDraggingOverDocument( false );
setType();
},
onDragEnter() {
setIsDraggingOverElement( true );
},
onDragLeave() {
setIsDraggingOverElement( false );
},
} );
const disableMotion = useReducedMotion();
let children;
const backdrop = {
hidden: { scaleY: 0, opacity: 0 },
show: {
scaleY: 1,
opacity: 1,
transition: {
type: 'tween',
duration: 0.2,
delay: 0.1,
delayChildren: 0.2,
},
},
exit: {
scaleY: 1,
opacity: 0,
transition: {
duration: 0.3,
delayChildren: 0,
},
},
};
const foreground = {
hidden: { opacity: 0, scale: 0.75 },
show: { opacity: 1, scale: 1 },
exit: { opacity: 0, scale: 0.9 },
};
if ( isDraggingOverElement ) {
children = (
<motion.div
variants={ backdrop }
initial={ disableMotion ? 'show' : 'hidden' }
animate="show"
exit={ disableMotion ? 'show' : 'exit' }
className="components-drop-zone__content"
>
<motion.div variants={ foreground }>
<Icon
icon={ upload }
className="components-drop-zone__content-icon"
/>
<span className="components-drop-zone__content-text">
{ label ? label : __( '拖文件至此可上传' ) }
</span>
</motion.div>
</motion.div>
);
}
const classes = classnames( 'components-drop-zone', className, {
'is-active':
( isDraggingOverDocument || isDraggingOverElement ) &&
( ( type === 'file' && onFilesDrop ) ||
( type === 'html' && onHTMLDrop ) ||
( type === 'default' && onDrop ) ),
'is-dragging-over-document': isDraggingOverDocument,
'is-dragging-over-element': isDraggingOverElement,
[ `is-dragging-${ type }` ]: !! type,
} );
return (
<div ref={ ref } className={ classes }>
{ disableMotion ? (
children
) : (
<AnimatePresence>{ children }</AnimatePresence>
) }
</div>
);
}