diff --git a/src/app/AppContainer.js b/src/app/AppContainer.js index d50391b16b..855d503d64 100644 --- a/src/app/AppContainer.js +++ b/src/app/AppContainer.js @@ -6,6 +6,7 @@ import { moveBlockUpAction, moveBlockDownAction, deleteBlockAction, + createBlockAction, } from '../store/actions'; import MainApp from './MainApp'; @@ -31,6 +32,9 @@ const mapDispatchToProps = ( dispatch, ownProps ) => { deleteBlockAction: ( clientId ) => { dispatch( deleteBlockAction( clientId ) ); }, + createBlockAction: ( clientId, block ) => { + dispatch( createBlockAction( clientId, block ) ); + }, }; }; diff --git a/src/block-management/block-manager.js b/src/block-management/block-manager.js index 86708ca18a..20cb053bb3 100644 --- a/src/block-management/block-manager.js +++ b/src/block-management/block-manager.js @@ -8,13 +8,10 @@ import { Platform, Switch, Text, View, FlatList } from 'react-native'; import RecyclerViewList, { DataSource } from 'react-native-recyclerview-list'; import BlockHolder from './block-holder'; import { ToolbarButton } from './constants'; - import type { BlockType } from '../store/'; - import styles from './block-manager.scss'; - // Gutenberg imports -import { getBlockType, serialize } from '@wordpress/blocks'; +import { getBlockType, serialize, createBlock } from '@wordpress/blocks'; export type BlockListType = { onChange: ( clientId: string, attributes: mixed ) => void, @@ -22,6 +19,7 @@ export type BlockListType = { moveBlockUpAction: string => mixed, moveBlockDownAction: string => mixed, deleteBlockAction: string => mixed, + createBlockAction: ( string, BlockType ) => mixed, blocks: Array, aztechtml: string, refresh: boolean, @@ -73,6 +71,18 @@ export default class BlockManager extends React.Component this.state.dataSource.splice( dataSourceBlockIndex, 1 ); this.props.deleteBlockAction( clientId ); break; + case ToolbarButton.PLUS: + // TODO: direct access insertion: it would be nice to pass the dataSourceBlockIndex here, + // so in this way we know the new block should be inserted right after this one + // instead of being appended to the end. + // this.props.createBlockAction( uid, dataSourceBlockIndex ); + + // TODO: block type picker here instead of hardcoding a core/code block + const newBlock = createBlock( 'core/paragraph', { content: 'new test text for a core/paragraph block' } ); + const newBlockWithFocusedState = { ...newBlock, focused: false }; + this.state.dataSource.push( newBlockWithFocusedState ); + this.props.createBlockAction( newBlockWithFocusedState.clientId, newBlockWithFocusedState ); + break; case ToolbarButton.SETTINGS: // TODO: implement settings break; diff --git a/src/store/actions/ActionTypes.js b/src/store/actions/ActionTypes.js index 16c576fdfb..3080e4b595 100644 --- a/src/store/actions/ActionTypes.js +++ b/src/store/actions/ActionTypes.js @@ -10,5 +10,6 @@ export default { MOVE_UP: 'BLOCK_MOVE_UP_ACTION', MOVE_DOWN: 'BLOCK_MOVE_DOWN_ACTION', DELETE: 'BLOCK_DELETE_ACTION', + CREATE: 'BLOCK_CREATE_ACTION', }, }; diff --git a/src/store/actions/index.js b/src/store/actions/index.js index a29a698aaa..f7b7ce5f89 100644 --- a/src/store/actions/index.js +++ b/src/store/actions/index.js @@ -37,3 +37,9 @@ export const deleteBlockAction: BlockActionType = clientId => ( { type: ActionTypes.BLOCK.DELETE, clientId, } ); + +export const createBlockAction: BlockActionType = (clientId, block) => ( { + type: ActionTypes.BLOCK.CREATE, + block: block, + clientId, +} ); diff --git a/src/store/actions/test.js b/src/store/actions/test.js index 0923f4f6f2..4b3fdf423a 100644 --- a/src/store/actions/test.js +++ b/src/store/actions/test.js @@ -2,9 +2,16 @@ import * as actions from './'; import ActionTypes from './ActionTypes'; +// Gutenberg imports +import { createBlock } from '@wordpress/blocks'; +import { registerCoreBlocks } from '@gutenberg/core-blocks'; describe( 'Store', () => { describe( 'actions', () => { + beforeAll( () => { + registerCoreBlocks(); + } ); + it( 'should create an action to focus a block', () => { const action = actions.focusBlockAction( '1' ); expect( action.type ).toBeDefined(); @@ -32,5 +39,14 @@ describe( 'Store', () => { expect( action.type ).toEqual( ActionTypes.BLOCK.DELETE ); expect( action.clientId ).toEqual( '1' ); } ); + + it( 'should create an action to create a block', () => { + const newBlock = createBlock( 'core/code', { content: 'new test text for a core/code block' } ); + const action = actions.createBlockAction( '1', newBlock ); + expect( action.type ).toEqual( ActionTypes.BLOCK.CREATE ); + expect( action.clientId ).toEqual( '1' ); + expect( action.block ).toEqual( newBlock ); + } ); + } ); } ); diff --git a/src/store/reducers/index.js b/src/store/reducers/index.js index 1af2a6a752..46f14a8755 100644 --- a/src/store/reducers/index.js +++ b/src/store/reducers/index.js @@ -108,6 +108,12 @@ export const reducer = ( blocks.splice( index, 1 ); return { blocks: blocks, refresh: ! state.refresh }; } + case ActionTypes.BLOCK.CREATE: { + // TODO we need to set focused: true and search for the currently focused block and + // set that one to `focused: false`. + blocks.push(action.block); + return { blocks: blocks, refresh: ! state.refresh }; + } default: return state; }