Skip to content

Commit 54d4f63

Browse files
committed
[Block Editor]: Better block transforms organization
1 parent 74cd9f9 commit 54d4f63

File tree

1 file changed

+93
-24
lines changed

1 file changed

+93
-24
lines changed

packages/block-editor/src/components/block-switcher/block-transformations-menu.js

Lines changed: 93 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,61 @@ import {
77
getBlockMenuDefaultClassName,
88
switchToBlockType,
99
} from '@wordpress/blocks';
10-
import { useState } from '@wordpress/element';
10+
import { useState, useMemo } from '@wordpress/element';
1111

1212
/**
1313
* Internal dependencies
1414
*/
1515
import BlockIcon from '../block-icon';
1616
import PreviewBlockPopover from './preview-block-popover';
1717

18+
/**
19+
* Helper hook to group transformations to display them in a specific order in the UI.
20+
* For now we group only priority content driven transformations(ex. paragraph -> heading).
21+
*
22+
* Later on we could also group 'layout' transformations(ex. paragraph -> group) and
23+
* display them in different sections.
24+
*
25+
* @param {Object[]} possibleBlockTransformations The available block transformations.
26+
* @return {Record<string, Object[]>} The grouped block transformations.
27+
*/
28+
function useGroupedTransforms( possibleBlockTransformations ) {
29+
const priorityContentTranformationBlocks = {
30+
'core/paragraph': 1,
31+
'core/heading': 2,
32+
'core/list': 3,
33+
'core/quote': 4,
34+
};
35+
const transformations = useMemo( () => {
36+
const priorityTextTranformsNames = Object.keys(
37+
priorityContentTranformationBlocks
38+
);
39+
return possibleBlockTransformations.reduce(
40+
( accumulator, item ) => {
41+
const { name } = item;
42+
if ( priorityTextTranformsNames.includes( name ) ) {
43+
accumulator.priorityTextTransformations.push( item );
44+
} else {
45+
accumulator.restTransformations.push( item );
46+
}
47+
return accumulator;
48+
},
49+
{ priorityTextTransformations: [], restTransformations: [] }
50+
);
51+
}, [ possibleBlockTransformations ] );
52+
53+
// Order the priority text transformations.
54+
transformations.priorityTextTransformations.sort(
55+
( { name: currentName }, { name: nextName } ) => {
56+
return priorityContentTranformationBlocks[ currentName ] <
57+
priorityContentTranformationBlocks[ nextName ]
58+
? -1
59+
: 1;
60+
}
61+
);
62+
return transformations;
63+
}
64+
1865
const BlockTransformationsMenu = ( {
1966
className,
2067
possibleBlockTransformations,
@@ -23,6 +70,11 @@ const BlockTransformationsMenu = ( {
2370
} ) => {
2471
const [ hoveredTransformItemName, setHoveredTransformItemName ] =
2572
useState();
73+
74+
const { priorityTextTransformations, restTransformations } =
75+
useGroupedTransforms( possibleBlockTransformations );
76+
const needsTextTransformationsSeparator =
77+
priorityTextTransformations.length && restTransformations.length;
2678
return (
2779
<MenuGroup label={ __( 'Transform to' ) } className={ className }>
2880
{ hoveredTransformItemName && (
@@ -33,31 +85,48 @@ const BlockTransformationsMenu = ( {
3385
) }
3486
/>
3587
) }
36-
{ possibleBlockTransformations.map( ( item ) => {
37-
const { name, icon, title, isDisabled } = item;
38-
return (
39-
<MenuItem
40-
key={ name }
41-
className={ getBlockMenuDefaultClassName( name ) }
42-
onClick={ ( event ) => {
43-
event.preventDefault();
44-
onSelect( name );
45-
} }
46-
disabled={ isDisabled }
47-
onMouseLeave={ () =>
48-
setHoveredTransformItemName( null )
49-
}
50-
onMouseEnter={ () =>
51-
setHoveredTransformItemName( name )
52-
}
53-
>
54-
<BlockIcon icon={ icon } showColors />
55-
{ title }
56-
</MenuItem>
57-
);
58-
} ) }
88+
{ priorityTextTransformations.map( ( item ) => (
89+
<BlockTranformationItem
90+
key={ item.name }
91+
item={ item }
92+
onSelect={ onSelect }
93+
setHoveredTransformItemName={ setHoveredTransformItemName }
94+
/>
95+
) ) }
96+
{ !! needsTextTransformationsSeparator && <hr /> }
97+
{ restTransformations.map( ( item ) => (
98+
<BlockTranformationItem
99+
key={ item.name }
100+
item={ item }
101+
onSelect={ onSelect }
102+
setHoveredTransformItemName={ setHoveredTransformItemName }
103+
/>
104+
) ) }
59105
</MenuGroup>
60106
);
61107
};
62108

109+
function BlockTranformationItem( {
110+
item,
111+
onSelect,
112+
setHoveredTransformItemName,
113+
} ) {
114+
const { name, icon, title, isDisabled } = item;
115+
return (
116+
<MenuItem
117+
className={ getBlockMenuDefaultClassName( name ) }
118+
onClick={ ( event ) => {
119+
event.preventDefault();
120+
onSelect( name );
121+
} }
122+
disabled={ isDisabled }
123+
onMouseLeave={ () => setHoveredTransformItemName( null ) }
124+
onMouseEnter={ () => setHoveredTransformItemName( name ) }
125+
>
126+
<BlockIcon icon={ icon } showColors />
127+
{ title }
128+
</MenuItem>
129+
);
130+
}
131+
63132
export default BlockTransformationsMenu;

0 commit comments

Comments
 (0)