Skip to content

Commit

Permalink
Try: Don't show a clone when dragging. (#23024)
Browse files Browse the repository at this point in the history
* Try: Don't show a clone when dragging.

This is an experiment.

* Hide the block being moved.

* Remove clone, add shadow, polish comments.

* Add DraggableChip experience to block-draggable

* Hide dragging block to emulate a "lift" effect

* Only show the grab cursor when drag and drop is possible.

* Remove dead JS.

* Polish chip.

* Polish DraggableChip

* Leave clone logic

Co-authored-by: Jon Q <hello@jonquach.com>
Co-authored-by: Joen Asmussen <asmussen@gmail.com>
Co-authored-by: Ella van Durpe <ella@vandurpe.com>
  • Loading branch information
4 people authored Jun 25, 2020
1 parent 81a010f commit cc0128f
Show file tree
Hide file tree
Showing 13 changed files with 188 additions and 53 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* WordPress dependencies
*/
import { getBlockType } from '@wordpress/blocks';
import { useSelect } from '@wordpress/data';
import { Flex, FlexItem } from '@wordpress/components';
import { menu, handle } from '@wordpress/icons';

/**
* Internal dependencies
*/
import BlockIcon from '../block-icon';

export default function BlockDraggableChip( { clientIds } ) {
const icon = useSelect(
( select ) => {
const { getBlockName } = select( 'core/block-editor' );
const [ firstId ] = clientIds;
const blockName = getBlockName( firstId );
const isOfSameType = clientIds.every(
( id ) => getBlockName( id ) === blockName
);

if ( ! isOfSameType ) {
return menu;
}

return getBlockType( blockName ).icon;
},
[ clientIds ]
);

return (
<div className="block-editor-block-draggable-chip-wrapper">
<div className="block-editor-block-draggable-chip">
<Flex
justify="center"
className="block-editor-block-draggable-chip__content"
>
<FlexItem>
<BlockIcon icon={ handle } />
</FlexItem>
<FlexItem>
<BlockIcon icon={ icon } />
</FlexItem>
</Flex>
</div>
</div>
);
}
8 changes: 8 additions & 0 deletions packages/block-editor/src/components/block-draggable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import { useSelect, useDispatch } from '@wordpress/data';
import { useEffect, useRef } from '@wordpress/element';
import { getScrollContainer } from '@wordpress/dom';

/**
* Internal dependencies
*/
import BlockDraggableChip from './draggable-chip';

const SCROLL_INACTIVE_DISTANCE_PX = 50;
const SCROLL_INTERVAL_MS = 25;
const PIXELS_PER_SECOND_PER_DISTANCE = 5;
Expand Down Expand Up @@ -153,6 +158,9 @@ const BlockDraggable = ( {
onDragEnd();
}
} }
__experimentalDragComponent={
<BlockDraggableChip clientIds={ clientIds } />
}
>
{ ( { onDraggableStart, onDraggableEnd } ) => {
return children( {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* WordPress dependencies
*/
import { wordpress } from '@wordpress/icons';

/**
* Internal dependencies
*/
import { BlockDraggableChip } from '../draggable-chip';

export default { title: 'BlockEditor/BlockDraggable' };

export const _default = () => {
return <BlockDraggableChip icon={ wordpress } label="WordPress" />;
};
33 changes: 33 additions & 0 deletions packages/block-editor/src/components/block-draggable/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.block-editor-block-draggable-chip-wrapper {
position: absolute;
top: -$block-toolbar-height - $grid-unit-15;
}

.block-editor-block-draggable-chip {
background-color: $dark-gray-primary;
border-radius: $radius-block-ui;
border: $border-width solid $dark-gray-primary;
box-shadow: $shadow-popover;
color: $white;
cursor: grabbing;
display: inline-flex;
height: $block-toolbar-height;
min-width: $button-size * 2;
padding: 0 $grid-unit-15;
user-select: none;

svg {
fill: currentColor;
}

&__content {
margin: auto;
}
}

// This hides the block being dragged.
// The effect is that the block being dragged appears to be "lifted".
.is-dragging.is-selected {
display: none !important;
}

9 changes: 6 additions & 3 deletions packages/block-editor/src/components/block-list/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -590,10 +590,13 @@
.components-button.has-icon.block-editor-block-mover-button.block-editor-block-mover-button {
min-width: $button-size;
width: $button-size;
cursor: grab;

&:active {
cursor: grabbing;
[draggable="true"] & {
cursor: grab;

&:active {
cursor: grabbing;
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/block-editor/src/components/block-toolbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
import { useRef } from '@wordpress/element';
import { useViewportMatch } from '@wordpress/compose';
import { hasBlockSupport } from '@wordpress/blocks';
import { getBlockType, hasBlockSupport } from '@wordpress/blocks';

/**
* Internal dependencies
Expand All @@ -32,7 +33,6 @@ export default function BlockToolbar( { hideDragHandle } ) {
isVisual,
moverDirection,
} = useSelect( ( select ) => {
const { getBlockType } = select( 'core/blocks' );
const {
getBlockName,
getBlockMode,
Expand Down
19 changes: 0 additions & 19 deletions packages/block-editor/src/components/block-toolbar/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -103,22 +103,3 @@
display: block;
}
}

// Show a draggable handle when you're dragging using the toolbar component.
.block-editor-block-toolbar__drag-clone::before {
content: "";
display: block;
position: absolute;
top: -$block-toolbar-height - $grid-unit-15;
width: $button-size * 2;
height: $block-toolbar-height;
border-radius: $radius-block-ui;
background-color: $dark-gray-primary;
border: $border-width solid $dark-gray-primary;

// This should be reconsidered if successful.
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTcgMTYuNWgxMFYxNUg3djEuNXptMC05VjloMTBWNy41SDd6IiBmaWxsPSIjZmZmIi8+PC9zdmc+);
background-size: $icon-size;
background-repeat: no-repeat;
background-position: center center;
}
1 change: 1 addition & 0 deletions packages/block-editor/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
@import "./components/block-breadcrumb/style.scss";
@import "./components/block-card/style.scss";
@import "./components/block-compare/style.scss";
@import "./components/block-draggable/style.scss";
@import "./components/block-mobile-toolbar/style.scss";
@import "./components/block-mover/style.scss";
@import "./components/block-navigation/style.scss";
Expand Down
81 changes: 59 additions & 22 deletions packages/components/src/draggable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { noop } from 'lodash';
/**
* WordPress dependencies
*/
import { Component } from '@wordpress/element';
import { Component, createRef } from '@wordpress/element';
import { withSafeTimeout } from '@wordpress/compose';

const dragImageClass = 'components-draggable__invisible-drag-image';
Expand All @@ -22,6 +22,7 @@ class Draggable extends Component {
this.onDragOver = this.onDragOver.bind( this );
this.onDragEnd = this.onDragEnd.bind( this );
this.resetDragState = this.resetDragState.bind( this );
this.dragComponentRef = createRef();
}

componentWillUnmount() {
Expand Down Expand Up @@ -117,40 +118,60 @@ class Draggable extends Component {
const elementWrapper = element.parentNode;
const elementTopOffset = parseInt( elementRect.top, 10 );
const elementLeftOffset = parseInt( elementRect.left, 10 );
const clone = element.cloneNode( true );
clone.id = `clone-${ elementId }`;
this.cloneWrapper = document.createElement( 'div' );
this.cloneWrapper.classList.add( cloneWrapperClass );
if ( cloneClassname ) {
this.cloneWrapper.classList.add( cloneClassname );
}

this.cloneWrapper.style.width = `${
elementRect.width + clonePadding * 2
}px`;

if ( elementRect.height > cloneHeightTransformationBreakpoint ) {
// Scale down clone if original element is larger than 700px.
this.cloneWrapper.style.transform = 'scale(0.5)';
this.cloneWrapper.style.transformOrigin = 'top left';
// Position clone near the cursor.
this.cloneWrapper.style.top = `${ event.clientY - 100 }px`;
this.cloneWrapper.style.left = `${ event.clientX }px`;
} else {
// If a dragComponent is defined, the following logic will clone the
// HTML node and inject it into the cloneWrapper.
if ( this.dragComponentRef.current ) {
// Position clone right over the original element (20px padding).
this.cloneWrapper.style.top = `${
elementTopOffset - clonePadding
}px`;
this.cloneWrapper.style.left = `${
elementLeftOffset - clonePadding
}px`;
}

// Hack: Remove iFrames as it's causing the embeds drag clone to freeze
Array.from( clone.querySelectorAll( 'iframe' ) ).forEach( ( child ) =>
child.parentNode.removeChild( child )
);
const clonedDragComponent = document.createElement( 'div' );
clonedDragComponent.innerHTML = this.dragComponentRef.current.innerHTML;
this.cloneWrapper.appendChild( clonedDragComponent );
} else {
const clone = element.cloneNode( true );
clone.id = `clone-${ elementId }`;

if ( elementRect.height > cloneHeightTransformationBreakpoint ) {
// Scale down clone if original element is larger than 700px.
this.cloneWrapper.style.transform = 'scale(0.5)';
this.cloneWrapper.style.transformOrigin = 'top left';
// Position clone near the cursor.
this.cloneWrapper.style.top = `${ event.clientY - 100 }px`;
this.cloneWrapper.style.left = `${ event.clientX }px`;
} else {
// Position clone right over the original element (20px padding).
this.cloneWrapper.style.top = `${
elementTopOffset - clonePadding
}px`;
this.cloneWrapper.style.left = `${
elementLeftOffset - clonePadding
}px`;
}

// Hack: Remove iFrames as it's causing the embeds drag clone to freeze
Array.from(
clone.querySelectorAll( 'iframe' )
).forEach( ( child ) => child.parentNode.removeChild( child ) );

this.cloneWrapper.appendChild( clone );
}

this.cloneWrapper.appendChild( clone );
// Inject the cloneWrapper into the DOM.
elementWrapper.appendChild( this.cloneWrapper );

// Mark the current cursor coordinates.
Expand Down Expand Up @@ -186,12 +207,28 @@ class Draggable extends Component {
}

render() {
const { children } = this.props;
const {
children,
__experimentalDragComponent: dragComponent,
} = this.props;

return children( {
onDraggableStart: this.onDragStart,
onDraggableEnd: this.onDragEnd,
} );
return (
<>
{ children( {
onDraggableStart: this.onDragStart,
onDraggableEnd: this.onDragEnd,
} ) }
{ dragComponent && (
<div
className="components-draggable-drag-component-root"
style={ { display: 'none' } }
ref={ this.dragComponentRef }
>
{ dragComponent }
</div>
) }
</>
);
}
}

Expand Down
7 changes: 0 additions & 7 deletions packages/components/src/draggable/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,4 @@ body.is-dragging-components-draggable {
background: transparent;
pointer-events: none;
z-index: z-index(".components-draggable__clone");
opacity: 0.7;

> * {
// This needs specificity as a theme is meant to define these by default.
margin-top: 0 !important;
margin-bottom: 0 !important;
}
}
1 change: 1 addition & 0 deletions packages/icons/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export { default as gallery } from './library/gallery';
export { default as globe } from './library/globe';
export { default as grid } from './library/grid';
export { default as group } from './library/group';
export { default as handle } from './library/handle';
export { default as heading } from './library/heading';
export { default as help } from './library/help';
export { default as inbox } from './library/inbox';
Expand Down
12 changes: 12 additions & 0 deletions packages/icons/src/library/handle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* WordPress dependencies
*/
import { Path, SVG } from '@wordpress/primitives';

const handle = (
<SVG viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<Path d="M7 16.5h10V15H7v1.5zm0-9V9h10V7.5H7z" />
</SVG>
);

export default handle;
1 change: 1 addition & 0 deletions storybook/main.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const stories = [
process.env.NODE_ENV !== 'test' && './stories/**/*.(js|mdx)',
'../packages/block-editor/src/**/stories/*.js',
'../packages/components/src/**/stories/*.js',
'../packages/icons/src/**/stories/*.js',
].filter( Boolean );
Expand Down

0 comments on commit cc0128f

Please sign in to comment.