Skip to content

Commit

Permalink
Add registry-aware controls
Browse files Browse the repository at this point in the history
  • Loading branch information
youknowriad committed Feb 8, 2019
1 parent 3e12a7a commit 8b07508
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 22 deletions.
8 changes: 4 additions & 4 deletions packages/core-data/src/controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* WordPress dependencies
*/
import { default as triggerApiFetch } from '@wordpress/api-fetch';
import { select as selectData } from '@wordpress/data';
import { createRegistryControl } from '@wordpress/data';

/**
* Trigger an API Fetch request.
Expand Down Expand Up @@ -37,9 +37,9 @@ const controls = {
return triggerApiFetch( request );
},

SELECT( { selectorName, args } ) {
return selectData( 'core' )[ selectorName ]( ...args );
},
SELECT: createRegistryControl( ( registry ) => ( { selectorName, args } ) => {
return registry.select( 'core' )[ selectorName ]( ...args );
} ),
};

export default controls;
15 changes: 14 additions & 1 deletion packages/data/src/factory.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Mark a function as a registry selector.
* Mark a selector as a registry selector.
*
* @param {function} registrySelector Function receiving a registry object and returning a state selector.
*
Expand All @@ -10,3 +10,16 @@ export function createRegistrySelector( registrySelector ) {

return registrySelector;
}

/**
* Mark a control as a registry control.
*
* @param {function} registryControl Function receiving a registry object and returning a control.
*
* @return {function} marked registry control.
*/
export function createRegistryControl( registryControl ) {
registryControl.isRegistryControl = true;

return registryControl;
}
2 changes: 1 addition & 1 deletion packages/data/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export { default as RegistryProvider, RegistryConsumer } from './components/regi
export { default as __experimentalAsyncModeProvider } from './components/async-mode-provider';
export { createRegistry } from './registry';
export { plugins };
export { createRegistrySelector } from './factory';
export { createRegistrySelector, createRegistryControl } from './factory';

/**
* The combineReducers helper function turns an object whose values are different
Expand Down
32 changes: 17 additions & 15 deletions packages/data/src/namespace-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,24 +105,26 @@ function createReduxStore( reducer, key, registry ) {
* @return {Object} Selectors mapped to the redux store provided.
*/
function mapSelectors( selectors, store, registry ) {
const createStateSelector = ( registeredSelector ) => function runSelector() {
const createStateSelector = ( registeredSelector ) => {
const selector = registeredSelector.isRegistrySelector ? registeredSelector( registry ) : registeredSelector;

// This function is an optimized implementation of:
//
// selector( store.getState(), ...arguments )
//
// Where the above would incur an `Array#concat` in its application,
// the logic here instead efficiently constructs an arguments array via
// direct assignment.
const argsLength = arguments.length;
const args = new Array( argsLength + 1 );
args[ 0 ] = store.getState();
for ( let i = 0; i < argsLength; i++ ) {
args[ i + 1 ] = arguments[ i ];
}
return function runSelector() {
// This function is an optimized implementation of:
//
// selector( store.getState(), ...arguments )
//
// Where the above would incur an `Array#concat` in its application,
// the logic here instead efficiently constructs an arguments array via
// direct assignment.
const argsLength = arguments.length;
const args = new Array( argsLength + 1 );
args[ 0 ] = store.getState();
for ( let i = 0; i < argsLength; i++ ) {
args[ i + 1 ] = arguments[ i ];
}

return selector( ...args );
return selector( ...args );
};
};

return mapValues( selectors, createStateSelector );
Expand Down
6 changes: 5 additions & 1 deletion packages/data/src/plugins/controls/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* External dependencies
*/
import { applyMiddleware } from 'redux';
import { mapValues } from 'lodash';

/**
* WordPress dependencies
Expand All @@ -14,7 +15,10 @@ export default function( registry ) {
const store = registry.registerStore( reducerKey, options );

if ( options.controls ) {
const middleware = createMiddleware( options.controls );
const normalizedControls = mapValues( options.controls, ( control ) => {
return control.isRegistryControl ? control( registry ) : control;
} );
const middleware = createMiddleware( normalizedControls );
const enhancer = applyMiddleware( middleware );
const createStore = () => store;

Expand Down
44 changes: 44 additions & 0 deletions packages/data/src/plugins/controls/test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Internal dependencies
*/
import { createRegistry } from '../../../registry';
import { createRegistryControl } from '../../../factory';
import controlsPlugin from '../';

describe( 'controls', () => {
let registry;

beforeEach( () => {
registry = createRegistry();
registry.use( controlsPlugin );
} );

describe( 'should call registry-aware controls', () => {
it( 'registers multiple selectors to the public API', () => {
const action1 = jest.fn( () => ( { type: 'NOTHING' } ) );
const action2 = function * () {
yield { type: 'DISPATCH', store: 'store1', action: 'action1' };
};
registry.registerStore( 'store1', {
reducer: () => 'state1',
actions: {
action1,
},
} );
registry.registerStore( 'store2', {
reducer: () => 'state2',
actions: {
action2,
},
controls: {
DISPATCH: createRegistryControl( ( reg ) => ( { store, action } ) => {
return reg.dispatch( store )[ action ]();
} ),
},
} );

registry.dispatch( 'store2' ).action2();
expect( action1 ).toBeCalled();
} );
} );
} );

0 comments on commit 8b07508

Please sign in to comment.