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 noisysocks committed Oct 29, 2019
1 parent 669da7a commit 2980cb9
Show file tree
Hide file tree
Showing 13 changed files with 284 additions and 42 deletions.
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading

0 comments on commit 2980cb9

Please sign in to comment.