Skip to content

Commit

Permalink
Introduce ExperimentalBlockEditorProvider (#47319)
Browse files Browse the repository at this point in the history
This commit introduces `ExperimentalBlockEditorProvider` that prevents mixing experimental editor settings and the public `BlockEditorProvider` component. The actual filtering is handled in a private `__experimentalUpdateSettings` selector in the block-editor store.

Experimental settings may still be set via a PHP plugin – limiting this vector would require a separate PR.

## Rationale

WordPress extenders cannot update the experimental block settings on their own. The `updateSettings()` actions of the `@wordpress/block-editor` store will filter out all the settings that are **not** a part of the public API. The only way to actually store them is via private action. `__experimentalUpdateSettings()`.

To privatize a block editor setting, add it to the `privateSettings` list in 
[/packages/block-editor/src/store/actions.js](/packages/block-editor/src/store/actions.js):

```js
const privateSettings = [
	'__unstableInserterMediaCategories',
	// List a block editor setting here to make it private
];
```

## Mobile apps

This commit updates a few `.native.js` files. Mobile apps choose to import the `.native.js` files over their `.js` counterparts whenever possible. At the same time, this PR introduced the expectation of having two extra named exports: `ExperimentalEditorProvider` and `ExperimentalBlockEditorProvider`. I updated the native files to export the regular Provider component under the experimental name. This works because the settings filtering is restricted to the web – it doesn't make sense in context of mobile apps anyway.

Co-authored-by: ntsekouras <[email protected]>
  • Loading branch information
adamziel and ntsekouras authored Jan 26, 2023
1 parent ff5beb5 commit 3e85c43
Show file tree
Hide file tree
Showing 31 changed files with 445 additions and 140 deletions.
13 changes: 13 additions & 0 deletions docs/contributors/code/coding-guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,19 @@ export function MyComponent() {
}
```

#### Experimental editor settings

WordPress extenders cannot update the experimental block settings on their own. The `updateSettings()` actions of the `@wordpress/block-editor` store will filter out all the settings that are **not** a part of the public API. The only way to actually store them is via private action. `__experimentalUpdateSettings()`.

To privatize a block editor setting, add it to the `privateSettings` list in [/packages/block-editor/src/store/actions.js](/packages/block-editor/src/store/actions.js):

```js
const privateSettings = [
'__unstableInserterMediaCategories',
// List a block editor setting here to make it private
];
```

#### Experimental block.json and theme.json APIs

As of today, there is no way to restrict the `block.json` and `theme.json` APIs
Expand Down
4 changes: 4 additions & 0 deletions package-lock.json

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

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Toolbar } from '@wordpress/components';
* Internal dependencies
*/
import BlockMover from '../';
import BlockEditorProvider from '../../provider';
import { ExperimentalBlockEditorProvider } from '../../provider';
import { store as blockEditorStore } from '../../../store';

registerCoreBlocks();
Expand All @@ -35,9 +35,9 @@ function Provider( { children } ) {

return (
<div style={ wrapperStyle }>
<BlockEditorProvider value={ blocks }>
<ExperimentalBlockEditorProvider value={ blocks }>
{ children }
</BlockEditorProvider>
</ExperimentalBlockEditorProvider>
</div>
);
}
Expand Down
16 changes: 11 additions & 5 deletions packages/block-editor/src/components/block-preview/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import deprecated from '@wordpress/deprecated';
/**
* Internal dependencies
*/
import BlockEditorProvider from '../provider';
import { ExperimentalBlockEditorProvider } from '../provider';
import AutoHeightBlockPreview from './auto';
import { store as blockEditorStore } from '../../store';
import { BlockListItems } from '../block-list';
Expand Down Expand Up @@ -66,13 +66,16 @@ export function BlockPreview( {
}

return (
<BlockEditorProvider value={ renderedBlocks } settings={ settings }>
<ExperimentalBlockEditorProvider
value={ renderedBlocks }
settings={ settings }
>
<AutoHeightBlockPreview
viewportWidth={ viewportWidth }
minHeight={ minHeight }
additionalStyles={ additionalStyles }
/>
</BlockEditorProvider>
</ExperimentalBlockEditorProvider>
);
}

Expand Down Expand Up @@ -126,12 +129,15 @@ export function useBlockPreview( {
);

const children = (
<BlockEditorProvider value={ renderedBlocks } settings={ settings }>
<ExperimentalBlockEditorProvider
value={ renderedBlocks }
settings={ settings }
>
<BlockListItems
renderAppender={ false }
__experimentalLayout={ __experimentalLayout }
/>
</BlockEditorProvider>
</ExperimentalBlockEditorProvider>
);

return {
Expand Down
18 changes: 9 additions & 9 deletions packages/block-editor/src/components/inserter/stories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Internal dependencies
*/
import BlockLibrary from '../library';
import BlockEditorProvider from '../../provider';
import { ExperimentalBlockEditorProvider } from '../../provider';
import { patternCategories, patterns, reusableBlocks } from './utils/fixtures';
import Inserter from '../';

Expand All @@ -16,11 +16,11 @@ export const libraryWithoutPatterns = () => {
display: 'inline-block',
};
return (
<BlockEditorProvider>
<ExperimentalBlockEditorProvider>
<div style={ wrapperStyle }>
<BlockLibrary showInserterHelpPanel />
</div>
</BlockEditorProvider>
</ExperimentalBlockEditorProvider>
);
};

Expand All @@ -32,7 +32,7 @@ export const libraryWithPatterns = () => {
display: 'inline-block',
};
return (
<BlockEditorProvider
<ExperimentalBlockEditorProvider
settings={ {
__experimentalBlockPatternCategories: patternCategories,
__experimentalBlockPatterns: patterns,
Expand All @@ -41,7 +41,7 @@ export const libraryWithPatterns = () => {
<div style={ wrapperStyle }>
<BlockLibrary showInserterHelpPanel />
</div>
</BlockEditorProvider>
</ExperimentalBlockEditorProvider>
);
};

Expand All @@ -53,7 +53,7 @@ export const libraryWithPatternsAndReusableBlocks = () => {
display: 'inline-block',
};
return (
<BlockEditorProvider
<ExperimentalBlockEditorProvider
settings={ {
__experimentalBlockPatternCategories: patternCategories,
__experimentalBlockPatterns: patterns,
Expand All @@ -63,7 +63,7 @@ export const libraryWithPatternsAndReusableBlocks = () => {
<div style={ wrapperStyle }>
<BlockLibrary showInserterHelpPanel />
</div>
</BlockEditorProvider>
</ExperimentalBlockEditorProvider>
);
};

Expand All @@ -75,7 +75,7 @@ export const quickInserter = () => {
display: 'inline-block',
};
return (
<BlockEditorProvider
<ExperimentalBlockEditorProvider
settings={ {
__experimentalBlockPatternCategories: patternCategories,
__experimentalBlockPatterns: patterns,
Expand All @@ -85,6 +85,6 @@ export const quickInserter = () => {
<div style={ wrapperStyle }>
<Inserter __experimentalIsQuick />
</div>
</BlockEditorProvider>
</ExperimentalBlockEditorProvider>
);
};
47 changes: 33 additions & 14 deletions packages/block-editor/src/components/provider/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,43 @@ import withRegistryProvider from './with-registry-provider';
import useBlockSync from './use-block-sync';
import { store as blockEditorStore } from '../../store';
import { BlockRefsProvider } from './block-refs-provider';
import { unlock } from '../../experiments';

/** @typedef {import('@wordpress/data').WPDataRegistry} WPDataRegistry */

function BlockEditorProvider( props ) {
const { children, settings } = props;
export const ExperimentalBlockEditorProvider = withRegistryProvider(
( props ) => {
const { children, settings, stripExperimentalSettings = false } = props;

const { updateSettings } = useDispatch( blockEditorStore );
useEffect( () => {
updateSettings( {
...settings,
__internalIsInitialized: true,
} );
}, [ settings ] );
const { __experimentalUpdateSettings } = unlock(
useDispatch( blockEditorStore )
);
useEffect( () => {
__experimentalUpdateSettings(
{
...settings,
__internalIsInitialized: true,
},
stripExperimentalSettings
);
}, [ settings ] );

// Syncs the entity provider with changes in the block-editor store.
useBlockSync( props );
// Syncs the entity provider with changes in the block-editor store.
useBlockSync( props );

return <BlockRefsProvider>{ children }</BlockRefsProvider>;
}
return <BlockRefsProvider>{ children }</BlockRefsProvider>;
}
);

export default withRegistryProvider( BlockEditorProvider );
export const BlockEditorProvider = ( props ) => {
return (
<ExperimentalBlockEditorProvider
{ ...props }
stripExperimentalSettings={ true }
>
{ props.children }
</ExperimentalBlockEditorProvider>
);
};

export default BlockEditorProvider;
7 changes: 4 additions & 3 deletions packages/block-editor/src/components/provider/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { BlockRefsProvider } from './block-refs-provider';

/** @typedef {import('@wordpress/data').WPDataRegistry} WPDataRegistry */

function BlockEditorProvider( props ) {
const BlockEditorProvider = withRegistryProvider( function ( props ) {
const { children, settings } = props;

const { updateSettings } = useDispatch( blockEditorStore );
Expand All @@ -26,6 +26,7 @@ function BlockEditorProvider( props ) {
useBlockSync( props );

return <BlockRefsProvider>{ children }</BlockRefsProvider>;
}
} );

export default withRegistryProvider( BlockEditorProvider );
export default BlockEditorProvider;
export { BlockEditorProvider as ExperimentalBlockEditorProvider };
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/**
* External dependencies
*/
import { render } from '@testing-library/react';
/**
* WordPress dependencies
*/
import { useRegistry } from '@wordpress/data';

/**
* Internal dependencies
*/
import { BlockEditorProvider, ExperimentalBlockEditorProvider } from '../';
import { store as blockEditorStore } from '../../../store';

const HasEditorSetting = ( props ) => {
const registry = useRegistry();
if ( props.setRegistry ) {
props.setRegistry( registry );
}
return <p>Test.</p>;
};

describe( 'BlockEditorProvider', () => {
let registry;
const setRegistry = ( reg ) => {
registry = reg;
};
beforeEach( () => {
registry = undefined;
} );
it( 'should strip experimental settings', async () => {
render(
<BlockEditorProvider
settings={ {
__unstableInserterMediaCategories: true,
} }
>
<HasEditorSetting setRegistry={ setRegistry } />
</BlockEditorProvider>
);
const settings = registry.select( blockEditorStore ).getSettings();
expect( settings ).not.toHaveProperty(
'__unstableInserterMediaCategories'
);
} );
it( 'should preserve stable settings', async () => {
render(
<BlockEditorProvider
settings={ {
stableSetting: 'https://example.com',
} }
>
<HasEditorSetting setRegistry={ setRegistry } />
</BlockEditorProvider>
);
const settings = registry.select( blockEditorStore ).getSettings();
expect( settings ).toHaveProperty( 'stableSetting' );
} );
} );

describe( 'ExperimentalBlockEditorProvider', () => {
let registry;
const setRegistry = ( reg ) => {
registry = reg;
};
beforeEach( () => {
registry = undefined;
} );
it( 'should preserve experimental settings', async () => {
render(
<ExperimentalBlockEditorProvider
settings={ {
__unstableInserterMediaCategories: true,
} }
>
<HasEditorSetting setRegistry={ setRegistry } />
</ExperimentalBlockEditorProvider>
);
const settings = registry.select( blockEditorStore ).getSettings();
expect( settings ).toHaveProperty(
'__unstableInserterMediaCategories'
);
} );
it( 'should preserve stable settings', async () => {
render(
<ExperimentalBlockEditorProvider
settings={ {
stableSetting: 'https://example.com',
} }
>
<HasEditorSetting setRegistry={ setRegistry } />
</ExperimentalBlockEditorProvider>
);
const settings = registry.select( blockEditorStore ).getSettings();
expect( settings ).toHaveProperty( 'stableSetting' );
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,17 @@ import { render } from '@testing-library/react';
import useBlockSync from '../use-block-sync';
import withRegistryProvider from '../with-registry-provider';
import * as blockEditorActions from '../../../store/actions';

import { store as blockEditorStore } from '../../../store';
jest.mock( '../../../store/actions', () => {
const actions = jest.requireActual( '../../../store/actions' );
return {
...actions,
resetBlocks: jest.fn( actions.resetBlocks ),
replaceInnerBlocks: jest.fn( actions.replaceInnerBlocks ),
setHasControlledInnerBlocks: jest.fn( actions.replaceInnerBlocks ),
};
} );

const TestWrapper = withRegistryProvider( ( props ) => {
if ( props.setRegistry ) {
Expand Down
Loading

1 comment on commit 3e85c43

@github-actions
Copy link

Choose a reason for hiding this comment

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

Flaky tests detected in 3e85c43.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/4018676421
📝 Reported issues:

Please sign in to comment.