Skip to content

Commit

Permalink
Inserter: Try showing a "line" between two blocks on hover to insert …
Browse files Browse the repository at this point in the history
…a new empty block (#5198)

* Inserter: Try showing a "line" between two blocks on hover to insert a new empty block
* Make the sibling inserter focusable
* Add the insertion point at the beginning of the post
  • Loading branch information
youknowriad authored Feb 26, 2018
1 parent 2957b51 commit 1232d37
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 24 deletions.
3 changes: 2 additions & 1 deletion edit-post/assets/stylesheets/_z-index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ $z-layers: (
'.components-panel__header': 1,
'.edit-post-meta-boxes-area.is-loading:before': 1,
'.edit-post-meta-boxes-area .spinner': 2,
'.blocks-format-toolbar__link-modal': 2,
'.editor-block-contextual-toolbar': 21,
'.editor-block-switcher__menu': 2,
'.components-popover__close': 2,
'.editor-block-list__insertion-point': 2,
'.blocks-format-toolbar__link-modal': 3,
'.editor-block-mover': 1,
'.blocks-gallery-item__inline-menu': 20,
'.editor-block-settings-menu__popover': 20, // Below the header
Expand Down
4 changes: 4 additions & 0 deletions edit-post/components/modes/visual-editor/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,7 @@
}
}
}

.edit-post-visual-editor .editor-block-list__layout > .editor-block-list__insertion-point {
max-width: $visual-editor-max-width + ( 2 * $block-mover-padding-visible );
}
6 changes: 5 additions & 1 deletion editor/components/block-list/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,11 @@ export class BlockListBlock extends Component {
// Insertion point can only be made visible when the side inserter is
// not present, and either the block is at the extent of a selection or
// is the last block in the top-level list rendering.
const shouldShowInsertionPoint = ! showSideInserter && ( isLastInSelection || ( isLast && ! rootUID ) );
const shouldShowInsertionPoint = (
( ! isMultiSelected && ! isLast ) ||
( isMultiSelected && isLastInSelection ) ||
( isLast && ! rootUID && ! isEmptyDefaultBlock )
);

// Generate the wrapper class names handling the different states of the block.
const wrapperClassName = classnames( 'editor-block-list__block', {
Expand Down
52 changes: 45 additions & 7 deletions editor/components/block-list/insertion-point.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,74 @@
*/
import { connect } from 'react-redux';

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { isUnmodifiedDefaultBlock } from '@wordpress/blocks';
import { Component } from '@wordpress/element';

/**
* Internal dependencies
*/
import {
getBlockIndex,
getBlockInsertionPoint,
isBlockInsertionPointVisible,
getBlockCount,
getBlock,
isTyping,
} from '../../store/selectors';
import {
insertDefaultBlock,
startTyping,
} from '../../store/actions';

function BlockInsertionPoint( { showInsertionPoint } ) {
if ( ! showInsertionPoint ) {
return null;
class BlockInsertionPoint extends Component {
constructor() {
super( ...arguments );
this.onClick = this.onClick.bind( this );
}
onClick() {
const { layout, rootUID, index, ...props } = this.props;
props.insertDefaultBlock( { layout }, rootUID, index );
props.startTyping();
}

render() {
const { showInsertionPoint, showInserter } = this.props;

return <div className="editor-block-list__insertion-point" />;
return (
<div className="editor-block-list__insertion-point">
{ showInsertionPoint && <div className="editor-block-list__insertion-point-indicator" /> }
{ showInserter && (
<button
className="editor-block-list__insertion-point-inserter"
onClick={ this.onClick }
aria-label={ __( 'Insert block' ) }
/>
) }
</div>
);
}
}

export default connect(
( state, { uid, rootUID } ) => {
const blockIndex = uid ? getBlockIndex( state, uid, rootUID ) : -1;
const insertIndex = blockIndex > -1 ? blockIndex + 1 : getBlockCount( state );
const insertIndex = blockIndex + 1;
const insertionPoint = getBlockInsertionPoint( state );
const block = uid ? getBlock( state, uid ) : null;

return {
showInsertionPoint: (
isBlockInsertionPointVisible( state ) &&
insertionPoint.index === insertIndex &&
insertionPoint.rootUID === rootUID
insertionPoint.rootUID === rootUID &&
( ! block || ! isUnmodifiedDefaultBlock( block ) )
),
showInserter: ! isTyping( state ),
index: insertIndex,
};
},
{ insertDefaultBlock, startTyping }
)( BlockInsertionPoint );
2 changes: 2 additions & 0 deletions editor/components/block-list/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { Component } from '@wordpress/element';
*/
import './style.scss';
import BlockListBlock from './block';
import BlockInsertionPoint from './insertion-point';
import BlockSelectionClearer from '../block-selection-clearer';
import DefaultBlockAppender from '../default-block-appender';
import {
Expand Down Expand Up @@ -215,6 +216,7 @@ class BlockListLayout extends Component {

return (
<BlockSelectionClearer className={ classes }>
{ !! blockUIDs.length && <BlockInsertionPoint /> }
{ map( blockUIDs, ( uid, blockIndex ) => (
<BlockListBlock
key={ 'block-' + uid }
Expand Down
59 changes: 54 additions & 5 deletions editor/components/block-list/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -371,21 +371,55 @@

.editor-block-list__insertion-point {
position: relative;
z-index: z-index( '.editor-block-list__insertion-point' );
}

.editor-block-list__insertion-point-indicator {
position: absolute;
top: 16px;
height: 2px;
left: 0;
right: 0;
background: $blue-medium-500;
}

.editor-block-list__insertion-point-inserter {
position: absolute;
background: none;
border: none;
display: block;
top: 0;
height: 34px; // Matches the whole empty space between two blocks
width: 100%;
cursor: pointer;

&:before {
position: absolute;
top: -1px;
top: 16px;
height: 2px;
left: 0;
right: 0;
background: $blue-medium-500;
left: $block-padding;
right: $block-padding;
background: $dark-gray-100;
content: '';
opacity: 0;
transition: opacity 0.1s linear 0.1s;
}

&:hover:before {
opacity: 1;
transition: opacity 0.2s linear 0.5s;
}

&:focus:before {
opacity: 1;
transition: opacity 0.2s linear;
}
}

.editor-block-list__block > .editor-block-list__insertion-point {
position: absolute;
bottom: -10px;
bottom: -19px;
height: 34px; // Matches the whole empty space between two blocks
top: auto;
left: 0;
right: 0;
Expand All @@ -396,6 +430,21 @@
}
}

.editor-block-list__layout > .editor-block-list__insertion-point {
position: relative;
margin-top: -15px;
margin-left: auto;
margin-right: auto;
top: -19px;
left: 0;
right: 0;

@include break-small {
left: $block-mover-padding-visible;
right: $block-mover-padding-visible;
}
}

.editor-block-list__block .editor-block-list__block-html-textarea {
display: block;
margin: 0;
Expand Down
4 changes: 2 additions & 2 deletions editor/components/default-block-appender/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { withContext } from '@wordpress/components';
*/
import './style.scss';
import BlockDropZone from '../block-drop-zone';
import { appendDefaultBlock, startTyping } from '../../store/actions';
import { insertDefaultBlock, startTyping } from '../../store/actions';
import { getBlock, getBlockCount } from '../../store/selectors';

export function DefaultBlockAppender( { isLocked, isVisible, onAppend, showPrompt } ) {
Expand Down Expand Up @@ -60,7 +60,7 @@ export default compose(
attributes = { layout };
}

dispatch( appendDefaultBlock( attributes, rootUID ) );
dispatch( insertDefaultBlock( attributes, rootUID ) );
dispatch( startTyping() );
},
} )
Expand Down
4 changes: 2 additions & 2 deletions editor/components/writing-flow/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
} from '../../store/selectors';
import {
multiSelect,
appendDefaultBlock,
insertDefaultBlock,
selectBlock,
} from '../../store/actions';

Expand Down Expand Up @@ -267,7 +267,7 @@ export default connect(
} ),
{
onMultiSelect: multiSelect,
onBottomReached: appendDefaultBlock,
onBottomReached: insertDefaultBlock,
onSelectBlock: selectBlock,
}
)( WritingFlow );
8 changes: 5 additions & 3 deletions editor/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -520,17 +520,19 @@ export function convertBlockToReusable( uid ) {
}
/**
* Returns an action object used in signalling that a new block of the default
* type should be appended to the block list.
* type should be added to the block list.
*
* @param {?Object} attributes Optional attributes of the block to assign.
* @param {?string} rootUID Optional root UID of block list to append.
* @param {?number} index Optional index where to insert the default block
*
* @return {Object} Action object
*/
export function appendDefaultBlock( attributes, rootUID ) {
export function insertDefaultBlock( attributes, rootUID, index ) {
return {
type: 'APPEND_DEFAULT_BLOCK',
type: 'INSERT_DEFAULT_BLOCK',
attributes,
rootUID,
index,
};
}
6 changes: 3 additions & 3 deletions editor/store/effects.js
Original file line number Diff line number Diff line change
Expand Up @@ -454,11 +454,11 @@ export default {
dispatch( saveReusableBlock( reusableBlock.id ) );
dispatch( replaceBlocks( [ oldBlock.uid ], [ newBlock ] ) );
},
APPEND_DEFAULT_BLOCK( action ) {
const { attributes, rootUID } = action;
INSERT_DEFAULT_BLOCK( action ) {
const { attributes, rootUID, index } = action;
const block = createBlock( getDefaultBlockName(), attributes );

return insertBlock( block, undefined, rootUID );
return insertBlock( block, index, rootUID );
},
CREATE_NOTICE( { notice: { content, spokenMessage } } ) {
const message = spokenMessage || content;
Expand Down

0 comments on commit 1232d37

Please sign in to comment.