Skip to content

Commit

Permalink
Merge pull request #226 from wordpress-mobile/add/gb-store
Browse files Browse the repository at this point in the history
Use Gutenberg store
  • Loading branch information
Tug committed Nov 15, 2018
2 parents 1924c04 + d7ea973 commit 5c2e876
Show file tree
Hide file tree
Showing 18 changed files with 672 additions and 773 deletions.
2 changes: 2 additions & 0 deletions jest/setup.js
Expand Up @@ -5,3 +5,5 @@ jest.mock( '../react-native-gutenberg-bridge', () => {
subscribeParentGetHtml: jest.fn(),
};
} );

jest.mock( 'react-native-recyclerview-list' );
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -13,6 +13,7 @@
"@babel/plugin-transform-runtime": "^7.1.0",
"@wordpress/babel-preset-default": "^1.1.2",
"@wordpress/block-serialization-spec-parser": "^1.0.0",
"@wordpress/jest-preset-default": "^3.0.2",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^8.2.2",
"babel-jest": "^23.6.0",
Expand Down Expand Up @@ -113,4 +114,4 @@
"tinycolor2": "^1.4.1",
"turbo-combine-reducers": "^1.0.2"
}
}
}
49 changes: 16 additions & 33 deletions src/app/App.js
Expand Up @@ -4,39 +4,22 @@
import '../globals';

import React from 'react';
import { Provider } from 'react-redux';
import { setupStore, html2State } from '../store';
import AppContainer from './AppContainer';
import { Store } from 'redux';

// Gutenberg imports
import { registerCoreBlocks } from '@wordpress/block-library';
import { registerBlockType, setUnregisteredTypeHandlerName } from '@wordpress/blocks';

import AppContainer from './AppContainer';
import initialHtml from './initial-html';

type PropsType = {
initialData: string | Store,
};
type StateType = {
store: Store,
};

export default class AppProvider extends React.Component<PropsType, StateType> {
state: StateType;

constructor( props: PropsType ) {
super( props );

this.state = {
store:
typeof props.initialData === 'object' ?
props.initialData :
setupStore( html2State( props.initialData !== undefined ? props.initialData : initialHtml ) ),
};
}

render() {
return (
<Provider store={ this.state.store }>
<AppContainer />
</Provider>
);
}
}
import * as UnsupportedBlock from '../block-types/unsupported-block/';

registerCoreBlocks();
registerBlockType( UnsupportedBlock.name, UnsupportedBlock.settings );
setUnregisteredTypeHandlerName( UnsupportedBlock.name );

const AppProvider = () => (
<AppContainer initialHtml={ initialHtml } />
);

export default AppProvider;
19 changes: 4 additions & 15 deletions src/app/App.test.js
Expand Up @@ -3,9 +3,8 @@
import renderer from 'react-test-renderer';

import App from './App';
import initialHtml from './initial-html';
import { html2State, setupStore } from '../store';
import BlockHolder from '../block-management/block-holder';
import { dispatch, select } from '@wordpress/data';

describe( 'App', () => {
it( 'renders without crashing', () => {
Expand All @@ -15,20 +14,10 @@ describe( 'App', () => {
} );

it( 'renders without crashing with a block focused', () => {
// construct a state object with the first block focused
const state = html2State( initialHtml );
const block0 = { ...state.blocks[ 0 ] };
block0.focused = true;
state.blocks[ 0 ] = block0;

// create a Store with the state object
const store = setupStore( state );

// render an App using the specified Store
const app = renderer.create( <App initialData={ store } /> );
const app = renderer.create( <App /> );
const blocks = select( 'core/editor' ).getBlocks();
dispatch( 'core/editor' ).selectBlock( blocks[ 0 ].clientId );
const rendered = app.toJSON();

// App should be rendered OK
expect( rendered ).toBeTruthy();
} );

Expand Down
178 changes: 129 additions & 49 deletions src/app/AppContainer.js
@@ -1,56 +1,136 @@
/** @flow
* @format */

import { connect } from 'react-redux';
import {
updateBlockAttributes,
focusBlockAction,
moveBlockUpAction,
moveBlockDownAction,
deleteBlockAction,
createBlockAction,
parseBlocksAction,
serializeToNativeAction,
mergeBlocksAction,
} from '../store/actions';
import MainApp from './MainApp';
import React from 'react';
import { parse, serialize } from '@wordpress/blocks';
import { withDispatch, withSelect } from '@wordpress/data';
import { compose } from '@wordpress/compose';
import RNReactNativeGutenbergBridge from 'react-native-gutenberg-bridge';
import type { BlockType } from '../store/types';

const mapStateToProps = ( state ) => ( {
...state,
} );

const mapDispatchToProps = ( dispatch, ownProps ) => {
return {
...ownProps,
onChange: ( clientId, attributes ) => {
dispatch( updateBlockAttributes( clientId, attributes ) );
},
focusBlockAction: ( clientId ) => {
dispatch( focusBlockAction( clientId ) );
},
moveBlockUpAction: ( clientId ) => {
dispatch( moveBlockUpAction( clientId ) );
},
moveBlockDownAction: ( clientId ) => {
dispatch( moveBlockDownAction( clientId ) );
},
deleteBlockAction: ( clientId ) => {
dispatch( deleteBlockAction( clientId ) );
},
createBlockAction: ( clientId, block, clientIdAbove ) => {
dispatch( createBlockAction( clientId, block, clientIdAbove ) );
},
parseBlocksAction: ( html ) => {
dispatch( parseBlocksAction( html ) );
},
serializeToNativeAction: () => {
dispatch( serializeToNativeAction() );
},
mergeBlocksAction: ( blockOneClientId, blockTwoClientId, block ) => {
dispatch( mergeBlocksAction( blockOneClientId, blockTwoClientId, block ) );
},
};
type PropsType = {
rootClientId: string,
isBlockSelected: string => boolean,
selectedBlockIndex: number,
blocks: Array<BlockType>,
onInsertBlock: ( BlockType, number, string ) => mixed,
onMerge: ( string, string ) => mixed,
onMoveDown: string => mixed,
onMoveUp: string => mixed,
onRemove: string => mixed,
onResetBlocks: Array<BlockType> => mixed,
onSelect: string => mixed,
onAttributesUpdate: ( string, mixed ) => mixed,
initialHtml: string,
};

const AppContainer = connect( mapStateToProps, mapDispatchToProps )( MainApp );
export default AppContainer;
class AppContainer extends React.Component<PropsType> {
constructor( props: PropsType ) {
super( props );

this.parseBlocksAction( props.initialHtml );
}

onChange = ( clientId, attributes ) => {
this.props.onAttributesUpdate( clientId, attributes );
};

focusBlockAction = ( clientId ) => {
this.props.onSelect( clientId );
};

moveBlockUpAction = ( clientId ) => {
this.props.onMoveUp( clientId );
};

moveBlockDownAction = ( clientId ) => {
this.props.onMoveDown( clientId );
};

deleteBlockAction = ( clientId ) => {
this.props.onRemove( clientId );
};

createBlockAction = ( clientId, block ) => {
this.props.onInsertBlock( block, this.props.selectedBlockIndex + 1, this.props.rootClientId );
};

parseBlocksAction = ( html = '' ) => {
const parsed = parse( html );
this.props.onResetBlocks( parsed );
};

serializeToNativeAction = () => {
const html = serialize( this.props.blocks );
RNReactNativeGutenbergBridge.provideToNative_Html( html );
};

mergeBlocksAction = ( blockOneClientId, blockTwoClientId ) => {
this.props.onMerge( blockOneClientId, blockTwoClientId );
};

render() {
return (
<MainApp
blocks={ this.props.blocks }
onChange={ this.onChange }
focusBlockAction={ this.focusBlockAction }
moveBlockUpAction={ this.moveBlockUpAction }
moveBlockDownAction={ this.moveBlockDownAction }
deleteBlockAction={ this.deleteBlockAction }
createBlockAction={ this.createBlockAction }
parseBlocksAction={ this.parseBlocksAction }
serializeToNativeAction={ this.serializeToNativeAction }
mergeBlocksAction={ this.mergeBlocksAction }
isBlockSelected={ this.props.isBlockSelected }
/>
);
}
}

export default compose( [
withSelect( ( select ) => {
const {
getBlockIndex,
getBlocks,
getSelectedBlockClientId,
isBlockSelected,
} = select( 'core/editor' );
const selectedBlockClientId = getSelectedBlockClientId();

return {
isBlockSelected,
selectedBlockIndex: getBlockIndex( selectedBlockClientId ),
blocks: getBlocks(),
};
} ),
withDispatch( ( dispatch ) => {
const {
clearSelectedBlock,
insertBlock,
mergeBlocks,
moveBlocksDown,
moveBlocksUp,
removeBlock,
resetBlocks,
selectBlock,
updateBlockAttributes,
} = dispatch( 'core/editor' );

return {
clearSelectedBlock,
onInsertBlock: insertBlock,
onMerge: mergeBlocks,
onMoveDown: moveBlocksDown,
onMoveUp: moveBlocksUp,
onRemove: removeBlock,
onResetBlocks: resetBlocks,
onSelect: ( clientId ) => {
clearSelectedBlock();
selectBlock( clientId );
},
onAttributesUpdate: updateBlockAttributes,
};
} ),
] )( AppContainer );
17 changes: 2 additions & 15 deletions src/block-management/block-holder.js
Expand Up @@ -7,7 +7,7 @@ import React from 'react';
import { View, Text, TouchableWithoutFeedback } from 'react-native';
import InlineToolbar from './inline-toolbar';

import type { BlockType } from '../store/';
import type { BlockType } from '../store/types';

import styles from './block-holder.scss';

Expand All @@ -23,20 +23,7 @@ type PropsType = BlockType & {
mergeBlocks: ( forward: boolean ) => void,
};

type StateType = {
selected: boolean,
focused: boolean,
};

export default class BlockHolder extends React.Component<PropsType, StateType> {
constructor( props: PropsType ) {
super( props );
this.state = {
selected: false,
focused: false,
};
}

export default class BlockHolder extends React.Component<PropsType> {
renderToolbarIfBlockFocused() {
if ( this.props.focused ) {
return (
Expand Down

0 comments on commit 5c2e876

Please sign in to comment.