diff --git a/editor/modes/visual-editor/block-list.js b/editor/modes/visual-editor/block-list.js
index e04c8dace616e5..c9b0ba868ec8eb 100644
--- a/editor/modes/visual-editor/block-list.js
+++ b/editor/modes/visual-editor/block-list.js
@@ -2,7 +2,6 @@
* External dependencies
*/
import { connect } from 'react-redux';
-import classnames from 'classnames';
import { throttle, reduce, noop } from 'lodash';
/**
@@ -11,7 +10,6 @@ import { throttle, reduce, noop } from 'lodash';
import { __ } from '@wordpress/i18n';
import { Component } from '@wordpress/element';
import { serialize, getDefaultBlockName, createBlock } from '@wordpress/blocks';
-import { IconButton } from '@wordpress/components';
import { keycodes } from '@wordpress/utils';
/**
@@ -19,7 +17,6 @@ import { keycodes } from '@wordpress/utils';
*/
import VisualEditorBlock from './block';
import BlockDropZone from './block-drop-zone';
-import Inserter from '../../inserter';
import {
getBlockUids,
getBlockInsertionPoint,
@@ -37,9 +34,7 @@ const { ENTER } = keycodes;
class VisualEditorBlockList extends Component {
constructor( props ) {
super( props );
- this.state = {
- showContinueWritingControls: false,
- };
+
this.onSelectionStart = this.onSelectionStart.bind( this );
this.onSelectionChange = this.onSelectionChange.bind( this );
this.onSelectionEnd = this.onSelectionEnd.bind( this );
@@ -50,7 +45,6 @@ class VisualEditorBlockList extends Component {
this.setLastClientY = this.setLastClientY.bind( this );
this.onPointerMove = throttle( this.onPointerMove.bind( this ), 250 );
this.onPlaceholderKeyDown = this.onPlaceholderKeyDown.bind( this );
- this.toggleContinueWritingControls = this.toggleContinueWritingControls.bind( this );
// Browser does not fire `*move` event when the pointer position changes
// relative to the document, so fire it with the last known position.
this.onScroll = () => this.onPointerMove( { clientY: this.lastClientY } );
@@ -199,15 +193,6 @@ class VisualEditorBlockList extends Component {
this.props.onInsertBlock( newBlock );
}
- insertBlock( name ) {
- const newBlock = createBlock( name );
- this.props.onInsertBlock( newBlock );
- }
-
- toggleContinueWritingControls( showContinueWritingControls ) {
- return () => this.setState( { showContinueWritingControls } );
- }
-
render() {
const {
blocks,
@@ -222,9 +207,6 @@ class VisualEditorBlockList extends Component {
...blocks.slice( insertionPoint ),
]
: blocks;
- const continueWritingClassname = classnames( 'editor-visual-editor__continue-writing', {
- 'is-showing-controls': this.state.showContinueWritingControls,
- } );
return (
@@ -260,29 +242,6 @@ class VisualEditorBlockList extends Component {
/>
}
-
-
- this.insertBlock( 'core/paragraph' ) }
- label={ __( 'Insert paragraph block' ) }
- >
- { __( 'Paragraph' ) }
-
- this.insertBlock( 'core/image' ) }
- label={ __( 'Insert image block' ) }
- >
- { __( 'Image' ) }
-
-
);
}
diff --git a/editor/modes/visual-editor/index.js b/editor/modes/visual-editor/index.js
index 70e248d8b42a13..6e31faff576e36 100644
--- a/editor/modes/visual-editor/index.js
+++ b/editor/modes/visual-editor/index.js
@@ -16,6 +16,7 @@ import { KeyboardShortcuts } from '@wordpress/components';
*/
import './style.scss';
import VisualEditorBlockList from './block-list';
+import VisualEditorInserter from './inserter';
import PostTitle from '../../post-title';
import WritingFlow from '../../writing-flow';
import TableOfContents from '../../table-of-contents';
@@ -104,6 +105,7 @@ class VisualEditor extends Component {
+
);
diff --git a/editor/modes/visual-editor/inserter.js b/editor/modes/visual-editor/inserter.js
new file mode 100644
index 00000000000000..db2ea83685e608
--- /dev/null
+++ b/editor/modes/visual-editor/inserter.js
@@ -0,0 +1,81 @@
+/**
+ * External dependencies
+ */
+import { connect } from 'react-redux';
+import classnames from 'classnames';
+
+/**
+ * WordPress dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import { IconButton } from '@wordpress/components';
+import { Component } from '@wordpress/element';
+import { createBlock } from '@wordpress/blocks';
+
+/**
+ * Internal dependencies
+ */
+import Inserter from '../../inserter';
+import { insertBlock } from '../../actions';
+
+export class VisualEditorInserter extends Component {
+ constructor() {
+ super( ...arguments );
+
+ this.showControls = this.toggleControls.bind( this, true );
+ this.hideControls = this.toggleControls.bind( this, false );
+ this.insertParagraph = this.insertBlock.bind( this, 'core/paragraph' );
+ this.insertImage = this.insertBlock.bind( this, 'core/image' );
+
+ this.state = {
+ isShowingControls: false,
+ };
+ }
+
+ toggleControls( isShowingControls ) {
+ this.setState( { isShowingControls } );
+ }
+
+ insertBlock( name ) {
+ const { onInsertBlock } = this.props;
+ onInsertBlock( createBlock( name ) );
+ }
+
+ render() {
+ const { isShowingControls } = this.state;
+ const classes = classnames( 'editor-visual-editor__inserter', {
+ 'is-showing-controls': isShowingControls,
+ } );
+
+ return (
+
+
+
+ { __( 'Paragraph' ) }
+
+
+ { __( 'Image' ) }
+
+
+ );
+ }
+}
+
+export default connect(
+ null,
+ { onInsertBlock: insertBlock },
+)( VisualEditorInserter );
diff --git a/editor/modes/visual-editor/style.scss b/editor/modes/visual-editor/style.scss
index 1f29f3cf0481c2..7c027ee679509d 100644
--- a/editor/modes/visual-editor/style.scss
+++ b/editor/modes/visual-editor/style.scss
@@ -459,7 +459,7 @@ $sticky-bottom-offset: 20px;
}
}
-.editor-visual-editor__continue-writing {
+.editor-visual-editor__inserter {
display: flex;
align-items: baseline;
max-width: $visual-editor-max-width + ( 2 * $block-mover-padding-visible );
diff --git a/editor/modes/visual-editor/test/inserter.js b/editor/modes/visual-editor/test/inserter.js
new file mode 100644
index 00000000000000..8d16992690820a
--- /dev/null
+++ b/editor/modes/visual-editor/test/inserter.js
@@ -0,0 +1,56 @@
+/**
+ * External dependencies
+ */
+import { shallow } from 'enzyme';
+
+/**
+ * Internal dependencies
+ */
+import { VisualEditorInserter } from '../inserter';
+
+describe( 'VisualEditorInserter', () => {
+ it( 'should show controls when receiving focus', () => {
+ const wrapper = shallow( );
+
+ wrapper.simulate( 'focus' );
+
+ expect( wrapper.state( 'isShowingControls' ) ).toBe( true );
+ } );
+
+ it( 'should hide controls when losing focus', () => {
+ const wrapper = shallow( );
+
+ wrapper.simulate( 'focus' );
+ wrapper.simulate( 'blur' );
+
+ expect( wrapper.state( 'isShowingControls' ) ).toBe( false );
+ } );
+
+ it( 'should insert paragraph block', () => {
+ const onInsertBlock = jest.fn();
+ const wrapper = shallow(
+
+ );
+
+ wrapper
+ .findWhere( ( node ) => node.prop( 'children' ) === 'Paragraph' )
+ .simulate( 'click' );
+
+ expect( onInsertBlock ).toHaveBeenCalled();
+ expect( onInsertBlock.mock.calls[ 0 ][ 0 ].name ).toBe( 'core/paragraph' );
+ } );
+
+ it( 'should insert image block', () => {
+ const onInsertBlock = jest.fn();
+ const wrapper = shallow(
+
+ );
+
+ wrapper
+ .findWhere( ( node ) => node.prop( 'children' ) === 'Image' )
+ .simulate( 'click' );
+
+ expect( onInsertBlock ).toHaveBeenCalled();
+ expect( onInsertBlock.mock.calls[ 0 ][ 0 ].name ).toBe( 'core/image' );
+ } );
+} );