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

Fix editor crash when converting block with visible styles to reusable (after a save and page reload) #29059

Merged
merged 4 commits into from
Mar 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 33 additions & 28 deletions packages/block-editor/src/components/block-inspector/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
PanelBody,
__experimentalUseSlot as useSlot,
} from '@wordpress/components';
import { withSelect } from '@wordpress/data';
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
Expand All @@ -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 (
<div className="block-editor-block-inspector">
Expand Down Expand Up @@ -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;
37 changes: 25 additions & 12 deletions packages/block-editor/src/components/block-styles/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down
32 changes: 32 additions & 0 deletions packages/e2e-tests/specs/editor/various/reusable-blocks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
} );
} );