@wordpress/block-editor
Version:
172 lines (153 loc) • 4.68 kB
JavaScript
/**
* External dependencies
*/
import clsx from 'clsx';
/**
* WordPress dependencies
*/
import {
__unstableMotion as motion,
__unstableAnimatePresence as AnimatePresence,
} from '@wordpress/components';
import { useReducedMotion } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import { store as blockEditorStore } from '../../store';
import { unlock } from '../../lock-unlock';
export function ZoomOutSeparator( {
clientId,
rootClientId = '',
position = 'top',
} ) {
const [ isDraggedOver, setIsDraggedOver ] = useState( false );
const {
sectionRootClientId,
sectionClientIds,
insertionPoint,
blockInsertionPointVisible,
blockInsertionPoint,
blocksBeingDragged,
} = useSelect( ( select ) => {
const {
getInsertionPoint,
getBlockOrder,
getSectionRootClientId,
isBlockInsertionPointVisible,
getBlockInsertionPoint,
getDraggedBlockClientIds,
} = unlock( select( blockEditorStore ) );
const root = getSectionRootClientId();
const sectionRootClientIds = getBlockOrder( root );
return {
sectionRootClientId: root,
sectionClientIds: sectionRootClientIds,
blockOrder: getBlockOrder( root ),
insertionPoint: getInsertionPoint(),
blockInsertionPoint: getBlockInsertionPoint(),
blockInsertionPointVisible: isBlockInsertionPointVisible(),
blocksBeingDragged: getDraggedBlockClientIds(),
};
}, [] );
const isReducedMotion = useReducedMotion();
if ( ! clientId ) {
return;
}
let isVisible = false;
const isSectionBlock =
rootClientId === sectionRootClientId &&
sectionClientIds &&
sectionClientIds.includes( clientId );
if ( ! isSectionBlock ) {
return null;
}
const hasTopInsertionPoint =
insertionPoint?.index === 0 &&
clientId === sectionClientIds[ insertionPoint.index ];
const hasBottomInsertionPoint =
insertionPoint &&
insertionPoint.hasOwnProperty( 'index' ) &&
clientId === sectionClientIds[ insertionPoint.index - 1 ];
// We want to show the zoom out separator in either of these conditions:
// 1. If the inserter has an insertion index set
// 2. We are dragging a pattern over an insertion point
if ( position === 'top' ) {
isVisible =
hasTopInsertionPoint ||
( blockInsertionPointVisible &&
blockInsertionPoint.index === 0 &&
clientId === sectionClientIds[ blockInsertionPoint.index ] );
}
if ( position === 'bottom' ) {
isVisible =
hasBottomInsertionPoint ||
( blockInsertionPointVisible &&
clientId ===
sectionClientIds[ blockInsertionPoint.index - 1 ] );
}
const blockBeingDraggedClientId = blocksBeingDragged[ 0 ];
const isCurrentBlockBeingDragged = blocksBeingDragged.includes( clientId );
const blockBeingDraggedIndex = sectionClientIds.indexOf(
blockBeingDraggedClientId
);
const blockBeingDraggedPreviousSiblingClientId =
blockBeingDraggedIndex > 0
? sectionClientIds[ blockBeingDraggedIndex - 1 ]
: null;
const isCurrentBlockPreviousSiblingOfBlockBeingDragged =
blockBeingDraggedPreviousSiblingClientId === clientId;
// The separators are visually top/bottom of the block, but in actual fact
// the "top" separator is the "bottom" separator of the previous block.
// Therefore, this logic hides the separator if the current block is being dragged
// or if the current block is the previous sibling of the block being dragged.
if (
isCurrentBlockBeingDragged ||
isCurrentBlockPreviousSiblingOfBlockBeingDragged
) {
isVisible = false;
}
return (
<AnimatePresence>
{ isVisible && (
<motion.div
initial={ { height: 0 } }
animate={ {
// Use a height equal to that of the zoom out frame size.
height: 'calc(1 * var(--wp-block-editor-iframe-zoom-out-frame-size) / var(--wp-block-editor-iframe-zoom-out-scale)',
} }
exit={ { height: 0 } }
transition={ {
type: 'tween',
duration: isReducedMotion ? 0 : 0.2,
ease: [ 0.6, 0, 0.4, 1 ],
} }
className={ clsx(
'block-editor-block-list__zoom-out-separator',
{
'is-dragged-over': isDraggedOver,
}
) }
data-is-insertion-point="true"
onDragOver={ () => setIsDraggedOver( true ) }
onDragLeave={ () => setIsDraggedOver( false ) }
>
<motion.div
initial={ { opacity: 0 } }
animate={ { opacity: 1 } }
exit={ { opacity: 0, transition: { delay: -0.125 } } }
transition={ {
ease: 'linear',
duration: 0.1,
delay: 0.125,
} }
>
{ __( 'Drop pattern.' ) }
</motion.div>
</motion.div>
) }
</AnimatePresence>
);
}