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

Components: Refactor insertIndex from Inserter component #4551

Closed
wants to merge 1 commit into from
Closed
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
19 changes: 16 additions & 3 deletions editor/components/block-list/sibling-inserter.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,36 @@ import {
} from '../../store/selectors';
import {
clearSelectedBlock,
setInsertionPointIndex,
} from '../../store/actions';

class BlockListSiblingInserter extends Component {
constructor() {
super( ...arguments );

this.forceVisibleWhileInserting = this.forceVisibleWhileInserting.bind( this );
this.onToggle = this.onToggle.bind( this );

this.state = {
isForcedVisible: false,
};
}

forceVisibleWhileInserting( isOpen ) {
/**
* Handles sibling inserter behaviors to occur when the inserter is opened
* or closed.
*
* @param {Boolean} isOpen Whether inserter is open.
*/
onToggle( isOpen ) {
// Set index at which insertion point should display
const { setInsertionPoint, insertIndex } = this.props;
setInsertionPoint( isOpen ? insertIndex : null );

// Prevent mouseout and blur while navigating the open inserter menu
// from causing the inserter to be unmounted.
this.setState( { isForcedVisible: isOpen } );

// Clear block selection when opening
if ( isOpen ) {
this.props.clearSelectedBlock();
}
Expand Down Expand Up @@ -68,7 +80,7 @@ class BlockListSiblingInserter extends Component {
key="inserter"
position="bottom"
insertIndex={ insertIndex }
onToggle={ this.forceVisibleWhileInserting }
onToggle={ this.onToggle }
/>
</div>
);
Expand All @@ -91,5 +103,6 @@ export default connect(
},
{
clearSelectedBlock,
setInsertionPoint: setInsertionPointIndex,
}
)( BlockListSiblingInserter );
143 changes: 62 additions & 81 deletions editor/components/inserter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,101 +2,77 @@
* External dependencies
*/
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { isEmpty } from 'lodash';
import { isEmpty, over } from 'lodash';

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { Dropdown, IconButton, withContext } from '@wordpress/components';
import { createBlock } from '@wordpress/blocks';
import { Component, compose } from '@wordpress/element';
import { compose } from '@wordpress/element';

/**
* Internal dependencies
*/
import InserterMenu from './menu';
import { getBlockInsertionPoint, getEditorMode } from '../../store/selectors';
import {
insertBlock,
hideInsertionPoint,
showInsertionPoint,
} from '../../store/actions';
import { insertBlock, toggleInsertionPointVisible } from '../../store/actions';

class Inserter extends Component {
constructor() {
super( ...arguments );

this.onToggle = this.onToggle.bind( this );
}

onToggle( isOpen ) {
const {
insertIndex,
onToggle,
} = this.props;

if ( isOpen ) {
this.props.showInsertionPoint( insertIndex );
} else {
this.props.hideInsertionPoint();
}
/**
* Component to render a block inserter.
*
* @param {Object} props Component props.
*
* @returns {void}
*/
function Inserter( props ) {
const {
position,
children,
onInsertBlock,
insertionPoint,
hasSupportedBlocks,
isLocked,
} = props;

// Surface toggle callback to parent component
if ( onToggle ) {
onToggle( isOpen );
}
if ( ! hasSupportedBlocks || isLocked ) {
return null;
}

render() {
const {
position,
children,
onInsertBlock,
insertionPoint,
hasSupportedBlocks,
isLocked,
} = this.props;
return (
<Dropdown
className="editor-inserter"
position={ position }
onToggle={ props.onToggle }
expandOnMobile
renderToggle={ ( { onToggle, isOpen } ) => (
<IconButton
icon="insert"
label={ __( 'Add block' ) }
onClick={ onToggle }
className="editor-inserter__toggle"
aria-haspopup="true"
aria-expanded={ isOpen }
>
{ children }
</IconButton>
) }
renderContent={ ( { onClose } ) => {
const onInsert = ( name, initialAttributes ) => {
onInsertBlock(
name,
initialAttributes,
insertionPoint
);

if ( ! hasSupportedBlocks || isLocked ) {
return null;
}
onClose();
};

return (
<Dropdown
className="editor-inserter"
position={ position }
onToggle={ this.onToggle }
expandOnMobile
renderToggle={ ( { onToggle, isOpen } ) => (
<IconButton
icon="insert"
label={ __( 'Add block' ) }
onClick={ onToggle }
className="editor-inserter__toggle"
aria-haspopup="true"
aria-expanded={ isOpen }
>
{ children }
</IconButton>
) }
renderContent={ ( { onClose } ) => {
const onInsert = ( name, initialAttributes ) => {
onInsertBlock(
name,
initialAttributes,
insertionPoint
);

onClose();
};

return <InserterMenu onSelect={ onInsert } />;
} }
/>
);
}
return <InserterMenu onSelect={ onInsert } />;
} }
/>
);
}

export default compose( [
Expand All @@ -107,17 +83,22 @@ export default compose( [
mode: getEditorMode( state ),
};
},
( dispatch ) => ( {
( dispatch, ownProps ) => ( {
onInsertBlock( name, initialAttributes, position ) {
dispatch( insertBlock(
createBlock( name, initialAttributes ),
position
) );
},
...bindActionCreators( {
showInsertionPoint,
hideInsertionPoint,
}, dispatch ),

onToggle: over( [
// Allow parent component to handle toggle, e.g. setting an
// insertion point prior to it being shown
ownProps.onToggle,

// Toggle insertion point visibility to new value
( isOpen ) => dispatch( toggleInsertionPointVisible( isOpen ) ),
] ),
} )
),
withContext( 'editor' )( ( settings ) => {
Expand Down
21 changes: 13 additions & 8 deletions editor/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,27 +199,32 @@ export function insertBlocks( blocks, position ) {
}

/**
* Returns an action object showing the insertion point at a given index
* Returns an action object used in signalling that the visibility of the
* insertion point is to be toggled.
*
* @param {Number?} index Index of the insertion point
* @param {Boolean} isVisible Whether the insertion point is visible.
*
* @returns {Object} Action object.
*/
export function showInsertionPoint( index ) {
export function toggleInsertionPointVisible( isVisible ) {
return {
type: 'SHOW_INSERTION_POINT',
index,
type: 'TOGGLE_INSERTION_POINT_VISIBLE',
isVisible,
};
}

/**
* Returns an action object hiding the insertion point
* Returns an action object used in signalling that the insertion point is to
* be shown at a given index.
*
* @param {Number?} index Index of the insertion point, or null to unset.
*
* @returns {Object} Action object.
*/
export function hideInsertionPoint() {
export function setInsertionPointIndex( index ) {
return {
type: 'HIDE_INSERTION_POINT',
type: 'SET_INSERTION_POINT_INDEX',
index,
};
}

Expand Down
10 changes: 6 additions & 4 deletions editor/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -495,11 +495,13 @@ export function blocksMode( state = {}, action ) {
*/
export function blockInsertionPoint( state = {}, action ) {
switch ( action.type ) {
case 'SHOW_INSERTION_POINT':
return { ...state, visible: true, position: action.index };
case 'TOGGLE_INSERTION_POINT_VISIBLE':
const { isVisible } = action;
return { ...state, isVisible };

case 'HIDE_INSERTION_POINT':
return { ...state, visible: false, position: null };
case 'SET_INSERTION_POINT_INDEX':
const { index } = action;
return { ...state, index };
}

return state;
Expand Down
25 changes: 4 additions & 21 deletions editor/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -945,9 +945,9 @@ export function getBlockInsertionPoint( state ) {
return state.editor.present.blockOrder.length;
}

const position = getBlockSiblingInserterPosition( state );
if ( null !== position ) {
return position;
const { index } = state.blockInsertionPoint;
if ( Number.isInteger( index ) ) {
return index;
}

const lastMultiSelectedBlock = getLastMultiSelectedBlockUid( state );
Expand All @@ -963,23 +963,6 @@ export function getBlockInsertionPoint( state ) {
return state.editor.present.blockOrder.length;
}

/**
* Returns the position at which the block inserter will insert a new adjacent
* sibling block, or null if the inserter is not actively visible.
*
* @param {Object} state Global application state
*
* @returns {?Number} Whether the inserter is currently visible.
*/
export function getBlockSiblingInserterPosition( state ) {
const { position } = state.blockInsertionPoint;
if ( ! Number.isInteger( position ) ) {
return null;
}

return position;
}

/**
* Returns true if we should show the block insertion point
*
Expand All @@ -988,7 +971,7 @@ export function getBlockSiblingInserterPosition( state ) {
* @returns {?Boolean} Whether the insertion point is visible or not.
*/
export function isBlockInsertionPointVisible( state ) {
return !! state.blockInsertionPoint.visible;
return !! state.blockInsertionPoint.isVisible;
}

/**
Expand Down
23 changes: 12 additions & 11 deletions editor/store/test/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ import {
replaceBlock,
insertBlock,
insertBlocks,
showInsertionPoint,
hideInsertionPoint,
toggleInsertionPointVisible,
setInsertionPointIndex,
editPost,
savePost,
trashPost,
Expand Down Expand Up @@ -245,19 +245,20 @@ describe( 'actions', () => {
} );
} );

describe( 'showInsertionPoint', () => {
it( 'should return the SHOW_INSERTION_POINT action', () => {
expect( showInsertionPoint( 1 ) ).toEqual( {
type: 'SHOW_INSERTION_POINT',
index: 1,
describe( 'toggleInsertionPointVisible', () => {
it( 'should return the TOGGLE_INSERTION_POINT_VISIBLE action', () => {
expect( toggleInsertionPointVisible( true ) ).toEqual( {
type: 'TOGGLE_INSERTION_POINT_VISIBLE',
isVisible: true,
} );
} );
} );

describe( 'hideInsertionPoint', () => {
it( 'should return the HIDE_INSERTION_POINT action', () => {
expect( hideInsertionPoint() ).toEqual( {
type: 'HIDE_INSERTION_POINT',
describe( 'setInsertionPointIndex', () => {
it( 'should return the SET_INSERTION_POINT_INDEX action', () => {
expect( setInsertionPointIndex( 1 ) ).toEqual( {
type: 'SET_INSERTION_POINT_INDEX',
index: 1,
} );
} );
} );
Expand Down
Loading