Skip to content

Commit

Permalink
Block Editor: Optimize the 'useBlockDisplayTitle' hook (#58250)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mamaduka authored Jan 26, 2024
1 parent 526bfe7 commit f591759
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 116 deletions.
171 changes: 86 additions & 85 deletions packages/block-editor/src/components/block-title/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,76 +13,52 @@ import { useSelect } from '@wordpress/data';
*/
import BlockTitle from '../';

const blockTypeMap = {
'name-not-exists': null,
'name-exists': { title: 'Block Title' },
'name-with-label': { title: 'Block With Label' },
'name-with-custom-label': { title: 'Block With Custom Label' },
'name-with-long-label': { title: 'Block With Long Label' },
'reusable-block': { title: 'Reusable Block' },
};

const blockLabelMap = {
'Block With Label': 'Test Label',
'Block With Long Label':
'This is a longer label than typical for blocks to have.',
'Block With Custom Label': 'A Custom Label like a Block Variation Label',
};

jest.mock( '@wordpress/blocks', () => {
return {
getBlockType( name ) {
switch ( name ) {
case 'name-not-exists':
return null;

case 'name-exists':
return { title: 'Block Title' };

case 'name-with-label':
return { title: 'Block With Label' };

case 'name-with-custom-label':
return { title: 'Block With Custom Label' };

case 'name-with-long-label':
return { title: 'Block With Long Label' };
}
isReusableBlock( { title } ) {
return title === 'Reusable Block';
},
__experimentalGetBlockLabel( { title } ) {
switch ( title ) {
case 'Block With Label':
return 'Test Label';

case 'Block With Long Label':
return 'This is a longer label than typical for blocks to have.';

case 'Block With Custom Label':
return 'A Custom Label like a Block Variation Label';

default:
return title;
}
return blockLabelMap[ title ] || title;
},
};
} );

jest.mock( '../../use-block-display-information', () => {
const resultsMap = {
'id-name-exists': { title: 'Block Title' },
'id-name-with-label': { title: 'Block With Label' },
'id-name-with-long-label': { title: 'Block With Long Label' },
};
return jest.fn( ( clientId ) => resultsMap[ clientId ] );
} );

jest.mock( '@wordpress/data/src/components/use-select', () => {
// This allows us to tweak the returned value on each test.
const mock = jest.fn();
return mock;
} );
// This allows us to tweak the returned value on each test.
jest.mock( '@wordpress/data/src/components/use-select', () => jest.fn() );

describe( 'BlockTitle', () => {
it( 'renders nothing if name is falsey', () => {
useSelect.mockImplementation( () => ( {
name: null,
attributes: null,
} ) );
useSelect.mockImplementation( () => null );

const { container } = render( <BlockTitle /> );

expect( container ).toBeEmptyDOMElement();
} );

it( 'renders nothing if block type does not exist', () => {
useSelect.mockImplementation( () => ( {
name: 'name-not-exists',
attributes: null,
} ) );
useSelect.mockImplementation( ( mapSelect ) =>
mapSelect( () => ( {
getBlockName: () => 'name-not-exists',
getBlockType: () => null,
} ) )
);

const { container } = render(
<BlockTitle clientId="afd1cb17-2c08-4e7a-91be-007ba7ddc3a1" />
Expand All @@ -92,45 +68,58 @@ describe( 'BlockTitle', () => {
} );

it( 'renders title if block type exists', () => {
useSelect.mockImplementation( () => ( {
name: 'name-exists',
attributes: null,
} ) );
useSelect.mockImplementation( ( mapSelect ) =>
mapSelect( () => ( {
getBlockName: () => 'name-exists',
getBlockType: ( name ) => blockTypeMap[ name ],
getBlockAttributes: () => null,
getActiveBlockVariation: () => null,
} ) )
);

render( <BlockTitle clientId="id-name-exists" /> );

expect( screen.getByText( 'Block Title' ) ).toBeVisible();
} );

it( 'renders label if it is set', () => {
useSelect.mockImplementation( () => ( {
name: 'name-with-label',
attributes: null,
} ) );
useSelect.mockImplementation( ( mapSelect ) =>
mapSelect( () => ( {
getBlockName: () => 'name-with-label',
getBlockType: ( name ) => blockTypeMap[ name ],
getBlockAttributes: () => null,
} ) )
);

render( <BlockTitle clientId="id-name-with-label" /> );

expect( screen.getByText( 'Test Label' ) ).toBeVisible();
} );

it( 'should prioritize reusable block title over title', () => {
useSelect.mockImplementation( () => ( {
name: 'name-with-label',
reusableBlockTitle: 'Reuse me!',
attributes: null,
} ) );
useSelect.mockImplementation( ( mapSelect ) =>
mapSelect( () => ( {
getBlockName: () => 'reusable-block',
getBlockType: ( name ) => blockTypeMap[ name ],
getBlockAttributes: () => ( { ref: 1 } ),
__experimentalGetReusableBlockTitle: () => 'Reuse me!',
} ) )
);

render( <BlockTitle clientId="id-name-with-label" /> );
render( <BlockTitle clientId="id-reusable-block" /> );

expect( screen.queryByText( 'Test Label' ) ).not.toBeInTheDocument();
expect( screen.getByText( 'Reuse me!' ) ).toBeVisible();
} );

it( 'should prioritize block label over title', () => {
useSelect.mockImplementation( () => ( {
name: 'name-with-custom-label',
attributes: null,
} ) );
useSelect.mockImplementation( ( mapSelect ) =>
mapSelect( () => ( {
getBlockName: () => 'name-with-custom-label',
getBlockType: ( name ) => blockTypeMap[ name ],
getBlockAttributes: () => null,
} ) )
);

render( <BlockTitle clientId="id-name-with-label" /> );

Expand All @@ -140,22 +129,31 @@ describe( 'BlockTitle', () => {
).toBeVisible();
} );

it( 'should default to block information title if no reusable title or block name is available', () => {
useSelect.mockImplementation( () => ( {
name: 'some-rando-name',
attributes: null,
} ) );
it( 'should default to block variation title if no reusable title or block name is available', () => {
useSelect.mockImplementation( ( mapSelect ) =>
mapSelect( () => ( {
getBlockName: () => 'name-exists',
getBlockType: ( name ) => blockTypeMap[ name ],
getBlockAttributes: () => null,
getActiveBlockVariation: () => ( {
title: 'Block Variation Label',
} ),
} ) )
);

render( <BlockTitle clientId="id-name-with-label" /> );
render( <BlockTitle clientId="id-name-exists" /> );

expect( screen.getByText( 'Block With Label' ) ).toBeVisible();
expect( screen.getByText( 'Block Variation Label' ) ).toBeVisible();
} );

it( 'truncates the label with custom truncate length', () => {
useSelect.mockImplementation( () => ( {
name: 'name-with-long-label',
attributes: null,
} ) );
useSelect.mockImplementation( ( mapSelect ) =>
mapSelect( () => ( {
getBlockName: () => 'name-with-long-label',
getBlockType: ( name ) => blockTypeMap[ name ],
getBlockAttributes: () => null,
} ) )
);

render(
<BlockTitle
Expand All @@ -168,10 +166,13 @@ describe( 'BlockTitle', () => {
} );

it( 'should not truncate the label if maximum length is undefined', () => {
useSelect.mockImplementation( () => ( {
name: 'name-with-long-label',
attributes: null,
} ) );
useSelect.mockImplementation( ( mapSelect ) =>
mapSelect( () => ( {
getBlockName: () => 'name-with-long-label',
getBlockType: ( name ) => blockTypeMap[ name ],
getBlockAttributes: () => null,
} ) )
);

render( <BlockTitle clientId="id-name-with-long-label" /> );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
*/
import { useSelect } from '@wordpress/data';
import {
getBlockType,
__experimentalGetBlockLabel as getBlockLabel,
isReusableBlock,
__experimentalGetBlockLabel as getBlockLabel,
store as blocksStore,
} from '@wordpress/blocks';

/**
* Internal dependencies
*/
import useBlockDisplayInformation from '../use-block-display-information';
import { store as blockEditorStore } from '../../store';

/**
Expand All @@ -35,49 +34,52 @@ export default function useBlockDisplayTitle( {
maximumLength,
context,
} ) {
const { attributes, name, reusableBlockTitle } = useSelect(
const blockTitle = useSelect(
( select ) => {
if ( ! clientId ) {
return {};
return null;
}

const {
getBlockName,
getBlockAttributes,
__experimentalGetReusableBlockTitle,
} = select( blockEditorStore );
const { getBlockType, getActiveBlockVariation } =
select( blocksStore );

const blockName = getBlockName( clientId );
if ( ! blockName ) {
return {};
const blockType = getBlockType( blockName );
if ( ! blockType ) {
return null;
}
const isReusable = isReusableBlock( getBlockType( blockName ) );
return {
attributes: getBlockAttributes( clientId ),
name: blockName,
reusableBlockTitle:
isReusable &&
__experimentalGetReusableBlockTitle(
getBlockAttributes( clientId ).ref
),
};

const attributes = getBlockAttributes( clientId );
const isReusable = isReusableBlock( blockType );
const reusableBlockTitle = isReusable
? __experimentalGetReusableBlockTitle( attributes.ref )
: null;

if ( reusableBlockTitle ) {
return reusableBlockTitle;
}

const label = getBlockLabel( blockType, attributes, context );
// If the label is defined we prioritize it over a possible block variation title match.
if ( label !== blockType.title ) {
return label;
}

const match = getActiveBlockVariation( blockName, attributes );
// Label will fallback to the title if no label is defined for the current label context.
return match?.title || blockType.title;
},
[ clientId ]
[ clientId, context ]
);

const blockInformation = useBlockDisplayInformation( clientId );
if ( ! name || ! blockInformation ) {
if ( ! blockTitle ) {
return null;
}
const blockType = getBlockType( name );
const blockLabel = blockType
? getBlockLabel( blockType, attributes, context )
: null;

const label = reusableBlockTitle || blockLabel;
// Label will fallback to the title if no label is defined for the current
// label context. If the label is defined we prioritize it over a
// possible block variation title match.
const blockTitle =
label && label !== blockType.title ? label : blockInformation.title;

if (
maximumLength &&
Expand Down

0 comments on commit f591759

Please sign in to comment.