diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js
index a91c072d94cc76..2a8f7ffeb40dbc 100644
--- a/packages/block-editor/src/components/block-inspector/index.js
+++ b/packages/block-editor/src/components/block-inspector/index.js
@@ -12,7 +12,7 @@ import {
PanelBody,
__experimentalUseSlot as useSlot,
} from '@wordpress/components';
-import { withSelect } from '@wordpress/data';
+import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
@@ -29,14 +29,40 @@ import useBlockDisplayInformation from '../use-block-display-information';
import { store as blockEditorStore } from '../../store';
const BlockInspector = ( {
- blockType,
- count,
- hasBlockStyles,
- selectedBlockClientId,
- selectedBlockName,
showNoBlockSelectedMessage = true,
bubblesVirtually = true,
} ) => {
+ const {
+ count,
+ hasBlockStyles,
+ selectedBlockName,
+ selectedBlockClientId,
+ blockType,
+ } = useSelect( ( select ) => {
+ const {
+ getSelectedBlockClientId,
+ getSelectedBlockCount,
+ getBlockName,
+ } = select( blockEditorStore );
+ const { getBlockStyles } = select( blocksStore );
+
+ const _selectedBlockClientId = getSelectedBlockClientId();
+ const _selectedBlockName =
+ _selectedBlockClientId && getBlockName( _selectedBlockClientId );
+ const _blockType =
+ _selectedBlockName && getBlockType( _selectedBlockName );
+ const blockStyles =
+ _selectedBlockName && getBlockStyles( _selectedBlockName );
+
+ return {
+ count: getSelectedBlockCount(),
+ selectedBlockClientId: _selectedBlockClientId,
+ selectedBlockName: _selectedBlockName,
+ blockType: _blockType,
+ hasBlockStyles: blockStyles && blockStyles.length > 0,
+ };
+ }, [] );
+
if ( count > 1 ) {
return (
@@ -133,25 +159,4 @@ const AdvancedControls = ( { slotName, bubblesVirtually } ) => {
);
};
-export default withSelect( ( select ) => {
- const {
- getSelectedBlockClientId,
- getSelectedBlockCount,
- getBlockName,
- } = select( blockEditorStore );
- const { getBlockStyles } = select( blocksStore );
- const selectedBlockClientId = getSelectedBlockClientId();
- const selectedBlockName =
- selectedBlockClientId && getBlockName( selectedBlockClientId );
- const blockType =
- selectedBlockClientId && getBlockType( selectedBlockName );
- const blockStyles =
- selectedBlockClientId && getBlockStyles( selectedBlockName );
- return {
- count: getSelectedBlockCount(),
- hasBlockStyles: blockStyles && blockStyles.length > 0,
- selectedBlockName,
- selectedBlockClientId,
- blockType,
- };
-} )( BlockInspector );
+export default BlockInspector;
diff --git a/packages/block-editor/src/components/block-styles/index.js b/packages/block-editor/src/components/block-styles/index.js
index 2bcf224506e315..dd438e0bfbad66 100644
--- a/packages/block-editor/src/components/block-styles/index.js
+++ b/packages/block-editor/src/components/block-styles/index.js
@@ -25,17 +25,25 @@ import { getActiveStyle, replaceActiveStyle } from './utils';
import BlockPreview from '../block-preview';
import { store as blockEditorStore } from '../../store';
-const useGenericPreviewBlock = ( block, type ) =>
- useMemo(
- () =>
- type.example
- ? getBlockFromExample( block.name, {
- attributes: type.example.attributes,
- innerBlocks: type.example.innerBlocks,
- } )
- : cloneBlock( block ),
- [ type.example ? block.name : block, type ]
- );
+const EMPTY_OBJECT = {};
+
+function useGenericPreviewBlock( block, type ) {
+ return useMemo( () => {
+ const example = type?.example;
+ const blockName = type?.name;
+
+ if ( example && blockName ) {
+ return getBlockFromExample( blockName, {
+ attributes: example.attributes,
+ innerBlocks: example.innerBlocks,
+ } );
+ }
+
+ if ( block ) {
+ return cloneBlock( block );
+ }
+ }, [ type?.example ? block?.name : block, type ] );
+}
function BlockStyles( {
clientId,
@@ -45,9 +53,14 @@ function BlockStyles( {
} ) {
const selector = ( select ) => {
const { getBlock } = select( blockEditorStore );
- const { getBlockStyles } = select( blocksStore );
const block = getBlock( clientId );
+
+ if ( ! block ) {
+ return EMPTY_OBJECT;
+ }
+
const blockType = getBlockType( block.name );
+ const { getBlockStyles } = select( blocksStore );
return {
block,
type: blockType,
diff --git a/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js b/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js
index d99aed303ba494..e1087a10fe3297 100644
--- a/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js
+++ b/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js
@@ -322,4 +322,36 @@ describe( 'Reusable blocks', () => {
// Check that there's only a paragraph.
expect( await getEditedPostContent() ).toMatchSnapshot();
} );
+
+ // Test for regressions of https://github.com/WordPress/gutenberg/issues/27243.
+ it( 'should allow a block with styles to be converted to a reusable block', async () => {
+ // Insert a quote and reload the page.
+ insertBlock( 'Quote' );
+ await saveDraft();
+ await page.reload();
+
+ // The quote block should have a visible preview in the sidebar for this test to be valid.
+ const quoteBlock = await page.waitForSelector(
+ '.block-editor-block-list__block[aria-label="Block: Quote"]'
+ );
+ await quoteBlock.click();
+ await openDocumentSettingsSidebar();
+ await page.waitForXPath(
+ '//*[@role="region"][@aria-label="Editor settings"]//button[.="Styles"]'
+ );
+
+ // Convert to reusable.
+ await clickBlockToolbarButton( 'Options' );
+ await clickMenuItem( 'Add to Reusable blocks' );
+ const nameInput = await page.waitForSelector(
+ reusableBlockNameInputSelector
+ );
+ await nameInput.click();
+ await page.keyboard.type( 'Block with styles' );
+ await page.keyboard.press( 'Enter' );
+ const reusableBlock = await page.waitForSelector(
+ '.block-editor-block-list__block[aria-label="Block: Reusable block"]'
+ );
+ expect( reusableBlock ).toBeTruthy();
+ } );
} );