Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prototype: move blocks between levels with keyboard #22453

Merged
merged 16 commits into from
Jun 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,18 @@ _Returns_

- `?string`: Block Template Lock

<a name="hasBlockMovingClientId" href="#hasBlockMovingClientId">#</a> **hasBlockMovingClientId**

Returns whether block moving mode is enabled.

_Parameters_

- _state_ `Object`: Editor state.

_Returns_

- `string`: Client Id of moving block.

<a name="hasInserterItems" href="#hasInserterItems">#</a> **hasInserterItems**

Determines whether there are items to show in the inserter.
Expand Down Expand Up @@ -1246,6 +1258,14 @@ _Parameters_

- _clientId_ `string`: Block client ID.

<a name="setBlockMovingClientId" href="#setBlockMovingClientId">#</a> **setBlockMovingClientId**

Generator that triggers an action used to enable or disable the block moving mode.

_Parameters_

- _hasBlockMovingClientId_ `(string|null)`: Enable/Disable block moving mode.

<a name="setHasControlledInnerBlocks" href="#setHasControlledInnerBlocks">#</a> **setHasControlledInnerBlocks**

Returns an action object that sets whether the block has controlled innerblocks.
Expand Down
6 changes: 6 additions & 0 deletions packages/block-editor/src/components/block-actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ export default function BlockActions( { clientIds, children } ) {
insertAfterBlock,
insertBeforeBlock,
flashBlock,
setBlockMovingClientId,
setNavigationMode,
} = useDispatch( 'core/block-editor' );

const notifyCopy = useNotifyCopy();
Expand All @@ -70,6 +72,10 @@ export default function BlockActions( { clientIds, children } ) {
onInsertAfter() {
insertAfterBlock( last( castArray( clientIds ) ) );
},
onMoveTo() {
setNavigationMode( true );
setBlockMovingClientId( clientIds[ 0 ] );
},
onGroup() {
if ( ! blocks.length ) {
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
Expand Down Expand Up @@ -36,16 +41,18 @@ function BlockSelectionButton( {
const {
__unstableGetBlockWithoutInnerBlocks,
getBlockIndex,
hasBlockMovingClientId,
} = select( 'core/block-editor' );
const index = getBlockIndex( clientId, rootClientId );
const { name, attributes } = __unstableGetBlockWithoutInnerBlocks(
clientId
);
return { index, name, attributes };
const blockMovingMode = hasBlockMovingClientId();
return { index, name, attributes, blockMovingMode };
},
[ clientId, rootClientId ]
);
const { index, name, attributes } = selected;
const { index, name, attributes, blockMovingMode } = selected;
const { setNavigationMode, removeBlock } = useDispatch(
'core/block-editor'
);
Expand Down Expand Up @@ -73,11 +80,15 @@ function BlockSelectionButton( {
moverDirection
);

const classNames = classnames(
'block-editor-block-list__block-selection-button',
{
'is-block-moving-mode': !! blockMovingMode,
}
);

return (
<div
className="block-editor-block-list__block-selection-button"
{ ...props }
>
<div className={ classNames } { ...props }>
<Button
ref={ ref }
onClick={ () => setNavigationMode( false ) }
Expand Down
43 changes: 43 additions & 0 deletions packages/block-editor/src/components/block-list/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,49 @@
.is-navigate-mode & .block-editor-block-list__block.is-hovered:not(.is-selected)::after {
box-shadow: 0 0 0 1px $light-gray-ui;
}

.is-block-moving-mode & .block-editor-block-list__block.has-child-selected {
box-shadow: 0 0 0 $border-width-focus var(--wp-admin-theme-color);
outline: $border-width-focus solid transparent;
}

.is-block-moving-mode & .block-editor-block-list__block.is-selected {

&::before {
content: "";
position: absolute;
z-index: 0;
pointer-events: none;
transition:
border-color 0.1s linear,
border-style 0.1s linear,
box-shadow 0.1s linear;
right: 0;
left: 0;
top: -$default-block-margin / 2;
border-radius: $radius-block-ui;
border-top: 4px solid $light-gray-secondary;
}

&::after {
content: none;
}
}

.is-block-moving-mode.can-insert-moving-block & .block-editor-block-list__block.is-selected {
&::before {
border-color: var(--wp-admin-theme-color);
}
}
}


.is-block-moving-mode.block-editor-block-list__block-selection-button {
// Should be invisible but not unfocusable.
opacity: 0;
font-size: 1px;
height: 1px;
padding: 0;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export function BlockSettingsDropdown( { clientIds, ...props } ) {
onInsertBefore,
onRemove,
onCopy,
onMoveTo,
blocks,
} ) => (
<DropdownMenu
Expand Down Expand Up @@ -131,6 +132,13 @@ export function BlockSettingsDropdown( { clientIds, ...props } ) {
</MenuItem>
</>
) }
{ ! isLocked && (
<MenuItem
onClick={ flow( onClose, onMoveTo ) }
>
{ __( 'Move To' ) }
</MenuItem>
) }
{ count === 1 && (
<BlockModeToggle
clientId={ firstBlockClientId }
Expand Down
81 changes: 78 additions & 3 deletions packages/block-editor/src/components/writing-flow/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 { useRef, useEffect } from '@wordpress/element';
import { useRef, useEffect, useState } from '@wordpress/element';
import {
computeCaretRect,
focus,
Expand All @@ -26,6 +26,8 @@ import {
TAB,
isKeyboardEvent,
ESCAPE,
ENTER,
SPACE,
} from '@wordpress/keycodes';
import { useSelect, useDispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
Expand Down Expand Up @@ -203,8 +205,12 @@ function selector( select ) {
hasMultiSelection,
getBlockOrder,
isNavigationMode,
hasBlockMovingClientId,
getBlockIndex,
getBlockRootClientId,
getClientIdsOfDescendants,
canInsertBlockType,
getBlockName,
isSelectionEnabled,
getBlockSelectionStart,
isMultiSelecting,
Expand All @@ -228,8 +234,12 @@ function selector( select ) {
hasMultiSelection: hasMultiSelection(),
blocks: getBlockOrder(),
isNavigationMode: isNavigationMode(),
hasBlockMovingClientId,
getBlockIndex,
getBlockRootClientId,
getClientIdsOfDescendants,
canInsertBlockType,
getBlockName,
isSelectionEnabled: isSelectionEnabled(),
blockSelectionStart: getBlockSelectionStart(),
isMultiSelecting: isMultiSelecting(),
Expand Down Expand Up @@ -270,23 +280,31 @@ export default function WritingFlow( { children } ) {
hasMultiSelection,
blocks,
isNavigationMode,
hasBlockMovingClientId,
isSelectionEnabled,
blockSelectionStart,
isMultiSelecting,
getBlockIndex,
getBlockRootClientId,
getClientIdsOfDescendants,
canInsertBlockType,
getBlockName,
} = useSelect( selector, [] );
const {
multiSelect,
selectBlock,
clearSelectedBlock,
setNavigationMode,
setBlockMovingClientId,
moveBlockToPosition,
} = useDispatch( 'core/block-editor' );

const [ canInsertMovingBlock, setCanInsertMovingBlock ] = useState( false );

function onMouseDown( event ) {
verticalRect.current = null;

// Clicking inside a selected block should exit navigation mode.
// Clicking inside a selected block should exit navigation mode and block moving mode.
if (
isNavigationMode &&
selectedBlockClientId &&
Expand All @@ -296,6 +314,18 @@ export default function WritingFlow( { children } ) {
)
) {
setNavigationMode( false );
setBlockMovingClientId( null );
} else if (
isNavigationMode &&
hasBlockMovingClientId() &&
getBlockClientId( event.target )
) {
setCanInsertMovingBlock(
canInsertBlockType(
getBlockName( hasBlockMovingClientId() ),
getBlockRootClientId( getBlockClientId( event.target ) )
)
);
}

// Multi-select blocks when Shift+clicking.
Expand Down Expand Up @@ -376,6 +406,8 @@ export default function WritingFlow( { children } ) {
const isRight = keyCode === RIGHT;
const isTab = keyCode === TAB;
const isEscape = keyCode === ESCAPE;
const isEnter = keyCode === ENTER;
const isSpace = keyCode === SPACE;
const isReverse = isUp || isLeft;
const isHorizontal = isLeft || isRight;
const isVertical = isUp || isDown;
Expand Down Expand Up @@ -409,7 +441,48 @@ export default function WritingFlow( { children } ) {
selectedBlockClientId,
] )[ 0 ] ?? selectedBlockClientId;
}

const startingBlockClientId = hasBlockMovingClientId();

if ( startingBlockClientId && focusedBlockUid ) {
setCanInsertMovingBlock(
canInsertBlockType(
getBlockName( startingBlockClientId ),
getBlockRootClientId( focusedBlockUid )
)
);
}
if ( isEscape && startingBlockClientId ) {
setBlockMovingClientId( null );
setCanInsertMovingBlock( false );
}
if ( ( isEnter || isSpace ) && startingBlockClientId ) {
const sourceRoot = getBlockRootClientId(
startingBlockClientId
);
const destRoot = getBlockRootClientId( selectedBlockClientId );
const sourceBlockIndex = getBlockIndex(
startingBlockClientId,
sourceRoot
);
let destinationBlockIndex = getBlockIndex(
selectedBlockClientId,
destRoot
);
if (
sourceBlockIndex < destinationBlockIndex &&
sourceRoot === destRoot
) {
destinationBlockIndex -= 1;
}
moveBlockToPosition(
startingBlockClientId,
sourceRoot,
destRoot,
destinationBlockIndex
);
selectBlock( startingBlockClientId );
setBlockMovingClientId( null );
}
if ( navigateDown || navigateUp || navigateOut || navigateIn ) {
if ( focusedBlockUid ) {
event.preventDefault();
Expand Down Expand Up @@ -611,6 +684,8 @@ export default function WritingFlow( { children } ) {

const className = classnames( 'block-editor-writing-flow', {
'is-navigate-mode': isNavigationMode,
'is-block-moving-mode': !! hasBlockMovingClientId(),
'can-insert-moving-block': canInsertMovingBlock,
} );

// Disable reason: Wrapper itself is non-interactive, but must capture
Expand Down
20 changes: 20 additions & 0 deletions packages/block-editor/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,26 @@ export function* setNavigationMode( isNavigationMode = true ) {
}
}

/**
* Generator that triggers an action used to enable or disable the block moving mode.
*
* @param {string|null} hasBlockMovingClientId Enable/Disable block moving mode.
*/
export function* setBlockMovingClientId( hasBlockMovingClientId = null ) {
yield {
type: 'SET_BLOCK_MOVING_MODE',
hasBlockMovingClientId,
};

if ( hasBlockMovingClientId ) {
speak(
__(
'Use the Tab key and Arrow keys to choose new block location. Use Left and Right Arrow keys to move between nesting levels. Once location is selected press Enter or Space to move the block.'
)
);
}
}

/**
* Generator that triggers an action used to duplicate a list of blocks.
*
Expand Down
19 changes: 19 additions & 0 deletions packages/block-editor/src/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1531,6 +1531,24 @@ export function isNavigationMode( state = false, action ) {
return state;
}

/**
* Reducer returning whether the block moving mode is enabled or not.
*
* @param {string|null} state Current state.
* @param {Object} action Dispatched action.
*
* @return {string|null} Updated state.
*/
export function hasBlockMovingClientId( state = null, action ) {
// Let inserting block always trigger Edit mode.

if ( action.type === 'SET_BLOCK_MOVING_MODE' ) {
return action.hasBlockMovingClientId;
}

return state;
}

/**
* Reducer return an updated state representing the most recent block attribute
* update. The state is structured as an object where the keys represent the
Expand Down Expand Up @@ -1639,6 +1657,7 @@ export default combineReducers( {
preferences,
lastBlockAttributesChange,
isNavigationMode,
hasBlockMovingClientId,
automaticChangeStatus,
highlightedBlock,
} );
Loading