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

Private experimental cross-module selectors and actions #44521

25 changes: 14 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/block-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"@wordpress/deprecated": "file:../deprecated",
"@wordpress/dom": "file:../dom",
"@wordpress/element": "file:../element",
"@wordpress/experiments": "file:../experiments",
"@wordpress/hooks": "file:../hooks",
"@wordpress/html-entities": "file:../html-entities",
"@wordpress/i18n": "file:../i18n",
Expand Down
8 changes: 4 additions & 4 deletions packages/block-editor/src/components/block-list/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import BlockHtml from './block-html';
import { useBlockProps } from './use-block-props';
import { store as blockEditorStore } from '../../store';
import { useLayout } from './layout';
import { unlock } from '../../experiments';
export const BlockListBlockContext = createContext();

/**
Expand Down Expand Up @@ -113,10 +114,9 @@ function BlockListBlock( {
!! __unstableGetContentLockingParent( clientId );
return {
themeSupportsLayout: getSettings().supportsLayout,
isContentBlock:
select( blocksStore ).__experimentalHasContentRoleAttribute(
name
),
isContentBlock: unlock(
select( blocksStore )
).__experimentalHasContentRoleAttribute( name ),
hasContentLockedParent: _hasContentLockedParent,
isContentLocking:
getTemplateLock( clientId ) === 'contentOnly' &&
Expand Down
9 changes: 9 additions & 0 deletions packages/block-editor/src/experiments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* WordPress dependencies
*/
import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/experiments';

export const { unlock } = __dangerousOptInToUnstableAPIsOnlyForCoreModules(
'I know using unstable features means my plugin or theme will inevitably break on the next WordPress release.',
'@wordpress/block-editor'
);
1 change: 1 addition & 0 deletions packages/blocks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@wordpress/deprecated": "file:../deprecated",
"@wordpress/dom": "file:../dom",
"@wordpress/element": "file:../element",
"@wordpress/experiments": "file:../experiments",
"@wordpress/hooks": "file:../hooks",
"@wordpress/html-entities": "file:../html-entities",
"@wordpress/i18n": "file:../i18n",
Expand Down
14 changes: 14 additions & 0 deletions packages/blocks/src/api/raw-handling/test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ import { getBlockContentSchemaFromTransforms, isPlain } from '../utils';
import { store as mockStore } from '../../../store';
import { STORE_NAME as mockStoreName } from '../../../store/constants';

jest.mock( '@wordpress/experiments', () => {
return {
__dangerousOptInToUnstableAPIsOnlyForCoreModules: () => {
return {
unlock: () => {
return {
registerPrivateActions: () => {},
registerPrivateSelectors: () => {},
};
},
};
},
};
} );
jest.mock( '@wordpress/data', () => {
return {
select: jest.fn( ( store ) => {
Expand Down
12 changes: 12 additions & 0 deletions packages/blocks/src/experiments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* WordPress dependencies
*/
import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/experiments';
import { experiments as dataExperiments } from '@wordpress/data';

export const { unlock } = __dangerousOptInToUnstableAPIsOnlyForCoreModules(
'I know using unstable features means my plugin or theme will inevitably break on the next WordPress release.',
'@wordpress/blocks'
);

export const { registerPrivateSelectors } = unlock( dataExperiments );
7 changes: 6 additions & 1 deletion packages/blocks/src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import * as selectors from './selectors';
import * as actions from './actions';
import { STORE_NAME } from './constants';

import { registerPrivateSelectors } from '../experiments';
const { __experimentalHasContentRoleAttribute, ...stableSelectors } = selectors;

/**
* Store definition for the blocks namespace.
*
Expand All @@ -20,8 +23,10 @@ import { STORE_NAME } from './constants';
*/
export const store = createReduxStore( STORE_NAME, {
reducer,
selectors,
selectors: stableSelectors,
actions,
} );

registerPrivateSelectors( store, { __experimentalHasContentRoleAttribute } );

register( store );
20 changes: 20 additions & 0 deletions packages/data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,26 @@ _Returns_

- `Object`: Object containing the action creators.

### experiments

The experimental APIs exposed by the `@wordpress/data` package.
Only available to core packages. These APIs are not stable and may
change without notice. Do not use outside of core.

_Usage_

```js
import { unlock } from '../experiments';
import { experiments as dataExperiments } from '@wordpress/data';
const { registerPrivateSelectors } = unlock( dataExperiments );

import { store as blockEditorStore } from './store';
import { __unstableSelectionHasUnmergeableBlock } from './store/selectors';
registerPrivateSelectors( store, {
__experimentalHasContentRoleAttribute,
} );
```
Comment on lines +525 to +529
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These selectors don't match, which adds confusion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah snap good spot, I'll fix this in #46131

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


### plugins

Object of available plugins to use with a registry.
Expand Down
1 change: 1 addition & 0 deletions packages/data/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@wordpress/compose": "file:../compose",
"@wordpress/deprecated": "file:../deprecated",
"@wordpress/element": "file:../element",
"@wordpress/experiments": "file:../experiments",
"@wordpress/is-shallow-equal": "file:../is-shallow-equal",
"@wordpress/priority-queue": "file:../priority-queue",
"@wordpress/redux-routine": "file:../redux-routine",
Expand Down
104 changes: 104 additions & 0 deletions packages/data/src/experiments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* WordPress dependencies
*/
import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/experiments';

export const { lock, unlock } =
__dangerousOptInToUnstableAPIsOnlyForCoreModules(
'I know using unstable features means my plugin or theme will inevitably break on the next WordPress release.',
'@wordpress/data'
);

/**
* Enables registering private actions and selectors on a store without exposing
* them as public API.
*
* Use it with the store descriptor object:
*
* ```js
* const store = createReduxStore( 'my-store', { ... } );
* registerPrivateActionsAndSelectors( store, {
* __experimentalAction: ( state ) => state.value,
* }, {
* __experimentalSelector: ( state ) => state.value,
* } );
* ```
*
* Once the selectors are registered, they can be accessed using the
* `unlock()` utility:
*
* ```js
* unlock( registry.dispatch( blockEditorStore ) ).__experimentalAction();
* unlock( registry.select( blockEditorStore ) ).__experimentalSelector();
* ```
*
* Note the objects returned by select() and dispatch() have the good old public
* methods, but the modules that opted-in to the private APIs can also "unlock"
* additional private selectors and actions.
*
* @example
*
* ```js
* // In the package exposing the private selectors:
*
* import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/experiments';
* export const { lock, unlock } = __dangerousOptInToUnstableAPIsOnlyForCoreModules( /* ... *\/ );
*
* import { experiments as dataExperiments } from '@wordpress/data';
* const { registerPrivateActionsAndSelectors } = unlock( dataExperiments );
*
* const store = registerStore( 'my-store', { /* ... *\/ } );
* registerPrivateActionsAndSelectors( store, {
* __experimentalAction: ( state ) => state.value,
* }, {
* __experimentalSelector: ( state ) => state.value,
* } );
*
* // In the package using the private selectors:
* import { store as blockEditorStore } from '@wordpress/block-editor';
* unlock( registry.select( blockEditorStore ) ).__experimentalSelector();
*
* // Or in a React component:
* useSelect( ( select ) => (
* unlock( select( blockEditorStore ) ).__experimentalSelector()
* ) );
* useDispatch( ( dispatch ) => {
* unlock( dispatch( blockEditorStore ) ).__experimentalAction()
* } );
* ```
*
* @param {Object} store The store descriptor to register the private selectors on.
* @param {Object} actions The private actions to register in a { actionName: ( ...args ) => action } format.
* @param {Object} selectors The private selectors to register in a { selectorName: ( state, ...args ) => data } format.
*/
export function registerPrivateActionsAndSelectors(
store,
actions = {},
selectors = {}
) {
lock( store, { actions, selectors } );
}

/**
* The experimental APIs exposed by the `@wordpress/data` package.
* Only available to core packages. These APIs are not stable and may
* change without notice. Do not use outside of core.
*
* @example
*
* ```js
* import { unlock } from '../experiments';
* import { experiments as dataExperiments } from '@wordpress/data';
* const { registerPrivateSelectors } = unlock( dataExperiments );
*
* import { store as blockEditorStore } from './store';
* import { __unstableSelectionHasUnmergeableBlock } from './store/selectors';
* registerPrivateSelectors( store, {
* __experimentalHasContentRoleAttribute
* } );
* ```
*/
export const experiments = {};
lock( experiments, {
registerPrivateActionsAndSelectors,
} );
2 changes: 2 additions & 0 deletions packages/data/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export { createRegistrySelector, createRegistryControl } from './factory';
export { controls } from './controls';
export { default as createReduxStore } from './redux-store';

export { experiments } from './experiments';

/**
* Object of available plugins to use with a registry.
*
Expand Down
Loading