Skip to content

Commit

Permalink
Add horizontal option for the block movers (#16615)
Browse files Browse the repository at this point in the history
* horizontal option for the mover, missing icons, broken hover

* we now have icons

* positioned the mover to the middle left

* horizontal mover on mobile

* vertical layout for horizontal movers

* drop block movers into block edit to enable inline movers

* implemented so as to not be a concern for the block implementer

* removes useless scss variable

* hiding the drag handle at block level

* renamed horizontalMover to moverOptions to incorporate separation of properties

* rafactores the mover options

* Initial CSS work to make the menu more manageable.

This moves to flex instead of grid, neutralizes margins, simplifies a few things.

* Make movers inline again.

* Further improve margins for child blocks.

* adds proper aliases in BlockEdit

* previxed options as experimental

* RTL movers

* removed the position option, marked option experimental

* labeled as experimental new mober and block list props

* refactored direction detection code for better readability, fixed some code alignment issues
  • Loading branch information
draganescu authored and hypest committed Nov 4, 2019
1 parent 12490f2 commit ff78d85
Show file tree
Hide file tree
Showing 13 changed files with 284 additions and 42 deletions.
Expand Up @@ -9,11 +9,11 @@ import { ifViewportMatches } from '@wordpress/viewport';
import BlockMover from '../block-mover';
import VisualEditorInserter from '../inserter';

function BlockMobileToolbar( { clientId } ) {
function BlockMobileToolbar( { clientId, moverDirection } ) {
return (
<div className="editor-block-list__block-mobile-toolbar block-editor-block-list__block-mobile-toolbar">
<VisualEditorInserter />
<BlockMover clientIds={ [ clientId ] } />
<BlockMover clientIds={ [ clientId ] } __experimentalOrientation={ moverDirection } />
</div>
);
}
Expand Down
42 changes: 27 additions & 15 deletions packages/block-editor/src/components/block-list/block.js
Expand Up @@ -67,6 +67,7 @@ function BlockListBlock( {
mode,
isFocusMode,
hasFixedToolbar,
moverDirection,
isLocked,
clientId,
rootClientId,
Expand Down Expand Up @@ -450,6 +451,20 @@ function BlockListBlock( {
};
}
const blockElementId = `block-${ clientId }`;
const blockMover = (
<BlockMover
clientIds={ clientId }
blockElementId={ blockElementId }
isHidden={ ! isSelected }
isDraggable={
isDraggable !== false &&
( ! isPartOfMultiSelection && isMovable )
}
onDragStart={ onDragStart }
onDragEnd={ onDragEnd }
__experimentalOrientation={ moverDirection }
/>
);

// We wrap the BlockEdit component in a div that hides it when editing in
// HTML mode. This allows us to render all of the ancillary pieces
Expand Down Expand Up @@ -511,22 +526,18 @@ function BlockListBlock( {
rootClientId={ rootClientId }
/>
{ isFirstMultiSelected && (
<BlockMultiControls rootClientId={ rootClientId } />
<BlockMultiControls
rootClientId={ rootClientId }
moverDirection={ moverDirection }
/>
) }
<div className="editor-block-list__block-edit block-editor-block-list__block-edit">
{ shouldRenderMovers && (
<BlockMover
clientIds={ clientId }
blockElementId={ blockElementId }
isHidden={ ! isSelected }
isDraggable={
isDraggable !== false &&
( ! isPartOfMultiSelection && isMovable )
}
onDragStart={ onDragStart }
onDragEnd={ onDragEnd }
/>
<div
className={ classnames(
'editor-block-list__block-edit block-editor-block-list__block-edit',
{ 'has-mover-inside': moverDirection === 'horizontal' },
) }
>
{ shouldRenderMovers && ( moverDirection === 'vertical' ) && blockMover }
{ shouldShowBreadcrumb && (
<BlockBreadcrumb
clientId={ clientId }
Expand Down Expand Up @@ -566,6 +577,7 @@ function BlockListBlock( {
{ isValid && mode === 'html' && (
<BlockHtml clientId={ clientId } />
) }
{ shouldRenderMovers && ( moverDirection === 'horizontal' ) && blockMover }
{ ! isValid && [
<BlockInvalidWarning
key="invalid-warning"
Expand All @@ -578,7 +590,7 @@ function BlockListBlock( {
</BlockCrashBoundary>
{ !! hasError && <BlockCrashWarning /> }
{ shouldShowMobileToolbar && (
<BlockMobileToolbar clientId={ clientId } />
<BlockMobileToolbar clientId={ clientId } moverDirection={ moverDirection } />
) }
</IgnoreNestedEvents>
</div>
Expand Down
2 changes: 2 additions & 0 deletions packages/block-editor/src/components/block-list/index.js
Expand Up @@ -195,6 +195,7 @@ class BlockList extends Component {
className,
blockClientIds,
rootClientId,
__experimentalMoverDirection: moverDirection = 'vertical',
isDraggable,
selectedBlockClientId,
multiSelectedBlockClientIds,
Expand Down Expand Up @@ -227,6 +228,7 @@ class BlockList extends Component {
blockRef={ this.setBlockRef }
onSelectionStart={ this.onSelectionStart }
isDraggable={ isDraggable }
moverDirection={ moverDirection }

// This prop is explicitely computed and passed down
// to avoid being impacted by the async mode
Expand Down
Expand Up @@ -11,6 +11,7 @@ import BlockMover from '../block-mover';
function BlockListMultiControls( {
multiSelectedBlockClientIds,
isSelecting,
moverDirection,
} ) {
if ( isSelecting ) {
return null;
Expand All @@ -19,6 +20,7 @@ function BlockListMultiControls( {
return (
<BlockMover
clientIds={ multiSelectedBlockClientIds }
__experimentalOrientation={ moverDirection }
/>
);
}
Expand Down
3 changes: 3 additions & 0 deletions packages/block-editor/src/components/block-list/style.scss
Expand Up @@ -101,6 +101,9 @@

.block-editor-block-list__block-edit {
position: relative;
&.has-mover-inside > [data-block] {
display: flex;
}

&::before {
z-index: z-index(".block-editor-block-list__block-edit::before");
Expand Down
12 changes: 12 additions & 0 deletions packages/block-editor/src/components/block-mover/icons.js
Expand Up @@ -9,12 +9,24 @@ export const upArrow = (
</SVG>
);

export const leftArrow = (
<SVG width="18" height="18" viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg">
<Path d="M4.5 9l5.6-5.7 1.4 1.5L7.3 9l4.2 4.2-1.4 1.5L4.5 9z" />
</SVG>
);

export const downArrow = (
<SVG width="18" height="18" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18">
<Polygon points="9,13.5 14.7,7.9 13.2,6.5 9,10.7 4.8,6.5 3.3,7.9 " />
</SVG>
);

export const rightArrow = (
<SVG width="18" height="18" viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg">
<Path d="M13.5 9L7.9 3.3 6.5 4.8 10.7 9l-4.2 4.2 1.4 1.5L13.5 9z" />
</SVG>
);

export const dragHandle = (
<SVG width="18" height="18" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18">
<Path d="M13,8c0.6,0,1-0.4,1-1s-0.4-1-1-1s-1,0.4-1,1S12.4,8,13,8z M5,6C4.4,6,4,6.4,4,7s0.4,1,1,1s1-0.4,1-1S5.6,6,5,6z M5,10
Expand Down
57 changes: 49 additions & 8 deletions packages/block-editor/src/components/block-mover/index.js
Expand Up @@ -7,7 +7,7 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { __, sprintf } from '@wordpress/i18n';
import { IconButton } from '@wordpress/components';
import { getBlockType } from '@wordpress/blocks';
import { Component } from '@wordpress/element';
Expand All @@ -18,7 +18,7 @@ import { withInstanceId, compose } from '@wordpress/compose';
* Internal dependencies
*/
import { getBlockMoverDescription } from './mover-description';
import { upArrow, downArrow, dragHandle } from './icons';
import { leftArrow, rightArrow, upArrow, downArrow, dragHandle } from './icons';
import { IconDragHandle } from './drag-handle';

export class BlockMover extends Component {
Expand All @@ -44,24 +44,55 @@ export class BlockMover extends Component {
}

render() {
const { onMoveUp, onMoveDown, isFirst, isLast, isDraggable, onDragStart, onDragEnd, clientIds, blockElementId, blockType, firstIndex, isLocked, instanceId, isHidden, rootClientId } = this.props;
const { onMoveUp, onMoveDown, __experimentalOrientation: orientation, isRTL, isFirst, isLast, isDraggable, onDragStart, onDragEnd, clientIds, blockElementId, blockType, firstIndex, isLocked, instanceId, isHidden, rootClientId } = this.props;
const { isFocused } = this.state;
const blocksCount = castArray( clientIds ).length;
if ( isLocked || ( isFirst && isLast && ! rootClientId ) ) {
return null;
}

const getArrowIcon = ( moveDirection ) => {
if ( moveDirection === 'up' ) {
if ( orientation === 'horizontal' ) {
return isRTL ? rightArrow : leftArrow;
}
return upArrow;
} else if ( moveDirection === 'down' ) {
if ( orientation === 'horizontal' ) {
return isRTL ? leftArrow : rightArrow;
}
return downArrow;
}
return null;
};

const getMovementDirection = ( moveDirection ) => {
if ( moveDirection === 'up' ) {
if ( orientation === 'horizontal' ) {
return isRTL ? 'right' : 'left';
}
return 'up';
} else if ( moveDirection === 'down' ) {
if ( orientation === 'horizontal' ) {
return isRTL ? 'left' : 'right';
}
return 'down';
}
return null;
};

// We emulate a disabled state because forcefully applying the `disabled`
// attribute on the button while it has focus causes the screen to change
// to an unfocused state (body as active element) without firing blur on,
// the rendering parent, leaving it unable to react to focus out.
return (
<div className={ classnames( 'editor-block-mover block-editor-block-mover', { 'is-visible': isFocused || ! isHidden } ) }>
<div className={ classnames( 'editor-block-mover block-editor-block-mover', { 'is-visible': isFocused || ! isHidden, 'is-horizontal': orientation === 'horizontal' } ) }>
<IconButton
className="editor-block-mover__control block-editor-block-mover__control"
onClick={ isFirst ? null : onMoveUp }
icon={ upArrow }
label={ __( 'Move up' ) }
icon={ getArrowIcon( 'up' ) }
// translators: %s: Horizontal direction of block movement ( left, right )
label={ sprintf( __( 'Move %s' ), getMovementDirection( 'up' ) ) }
aria-describedby={ `block-editor-block-mover__up-description-${ instanceId }` }
aria-disabled={ isFirst }
onFocus={ this.onFocus }
Expand All @@ -79,8 +110,9 @@ export class BlockMover extends Component {
<IconButton
className="editor-block-mover__control block-editor-block-mover__control"
onClick={ isLast ? null : onMoveDown }
icon={ downArrow }
label={ __( 'Move down' ) }
icon={ getArrowIcon( 'down' ) }
// translators: %s: Horizontal direction of block movement ( left, right )
label={ sprintf( __( 'Move %s' ), getMovementDirection( 'down' ) ) }
aria-describedby={ `block-editor-block-mover__down-description-${ instanceId }` }
aria-disabled={ isLast }
onFocus={ this.onFocus }
Expand All @@ -95,6 +127,8 @@ export class BlockMover extends Component {
isFirst,
isLast,
-1,
orientation,
isRTL,
)
}
</span>
Expand All @@ -107,6 +141,8 @@ export class BlockMover extends Component {
isFirst,
isLast,
1,
orientation,
isRTL,
)
}
</span>
Expand All @@ -125,12 +161,17 @@ export default compose(
const blockOrder = getBlockOrder( rootClientId );
const firstIndex = getBlockIndex( firstClientId, rootClientId );
const lastIndex = getBlockIndex( last( normalizedClientIds ), rootClientId );
const { getSettings } = select( 'core/block-editor' );
const {
isRTL,
} = getSettings();

return {
blockType: block ? getBlockType( block.name ) : null,
isLocked: getTemplateLock( rootClientId ) === 'all',
rootClientId,
firstIndex,
isRTL,
isFirst: firstIndex === 0,
isLast: lastIndex === blockOrder.length - 1,
};
Expand Down
Expand Up @@ -14,12 +14,30 @@ import { __, _n, sprintf } from '@wordpress/i18n';
* @param {boolean} isLast This is the last block.
* @param {number} dir Direction of movement (> 0 is considered to be going
* down, < 0 is up).
* @param {string} orientation The orientation of the block movers, vertical or
* horizontal.
* @param {boolean} isRTL True if current writing system is right to left.
*
* @return {string} Label for the block movement controls.
*/
export function getBlockMoverDescription( selectedCount, type, firstIndex, isFirst, isLast, dir ) {
export function getBlockMoverDescription( selectedCount, type, firstIndex, isFirst, isLast, dir, orientation, isRTL ) {
const position = ( firstIndex + 1 );

const getMovementDirection = ( moveDirection ) => {
if ( moveDirection === 'up' ) {
if ( orientation === 'horizontal' ) {
return isRTL ? 'right' : 'left';
}
return 'up';
} else if ( moveDirection === 'down' ) {
if ( orientation === 'horizontal' ) {
return isRTL ? 'left' : 'right';
}
return 'down';
}
return null;
};

if ( selectedCount > 1 ) {
return getMultiBlockMoverDescription( selectedCount, firstIndex, isFirst, isLast, dir );
}
Expand All @@ -32,35 +50,46 @@ export function getBlockMoverDescription( selectedCount, type, firstIndex, isFir
if ( dir > 0 && ! isLast ) {
// moving down
return sprintf(
// translators: 1: Type of block (i.e. Text, Image etc), 2: Position of selected block, 3: New position
__( 'Move %1$s block from position %2$d down to position %3$d' ),
// translators: 1: Type of block (i.e. Text, Image etc), 2: Position of selected block, 3: Direction of movement ( up, down, left, right ), 4: New position
__( 'Move %1$s block from position %2$d %3$s to position %4$d' ),
type,
position,
( position + 1 )
getMovementDirection( 'down' ),
( position + 1 ),
);
}

if ( dir > 0 && isLast ) {
// moving down, and is the last item
// translators: %s: Type of block (i.e. Text, Image etc)
return sprintf( __( 'Block %s is at the end of the content and can’t be moved down' ), type );
// translators: 1: Type of block (i.e. Text, Image etc), 2: Direction of movement ( up, down, left, right )
return sprintf(
__( 'Block %1$s is at the end of the content and can’t be moved %2$s' ),
type,
getMovementDirection( 'down' ),

);
}

if ( dir < 0 && ! isFirst ) {
// moving up
return sprintf(
// translators: 1: Type of block (i.e. Text, Image etc), 2: Position of selected block, 3: New position
__( 'Move %1$s block from position %2$d up to position %3$d' ),
// translators: 1: Type of block (i.e. Text, Image etc), 2: Position of selected block, 3: Direction of movement ( up, down, left, right ), 4: New position
__( 'Move %1$s block from position %2$d %3$s to position %4$d' ),
type,
position,
( position - 1 )
getMovementDirection( 'up' ),
( position - 1 ),
);
}

if ( dir < 0 && isFirst ) {
// moving up, and is the first item
// translators: %s: Type of block (i.e. Text, Image etc)
return sprintf( __( 'Block %s is at the beginning of the content and can’t be moved up' ), type );
// translators: 1: Type of block (i.e. Text, Image etc), 2: Direction of movement ( up, down, left, right )
return sprintf(
__( 'Block %1$s is at the beginning of the content and can’t be moved %2$s' ),
type,
getMovementDirection( 'up' ),
);
}
}

Expand Down

0 comments on commit ff78d85

Please sign in to comment.