Skip to content

Commit

Permalink
Show patterns in inserter for non-root level insert destinations (#28459
Browse files Browse the repository at this point in the history
)
  • Loading branch information
david-szabo97 authored Feb 9, 2021
1 parent 85d74aa commit 6d3c4b3
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ import usePatternsState from './hooks/use-patterns-state';
import BlockPatternList from '../block-patterns-list';

function BlockPatternsCategory( {
rootClientId,
onInsert,
selectedCategory,
onClickCategory,
} ) {
const [ allPatterns, allCategories, onClick ] = usePatternsState(
onInsert
onInsert,
rootClientId
);

// Remove any empty categories
Expand Down Expand Up @@ -120,9 +122,15 @@ function BlockPatternsCategory( {
);
}

function BlockPatternsTabs( { onInsert, onClickCategory, selectedCategory } ) {
function BlockPatternsTabs( {
rootClientId,
onInsert,
onClickCategory,
selectedCategory,
} ) {
return (
<BlockPatternsCategory
rootClientId={ rootClientId }
selectedCategory={ selectedCategory }
onInsert={ onInsert }
onClickCategory={ onClickCategory }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,25 @@ import { store as blockEditorStore } from '../../../store';
/**
* Retrieves the block patterns inserter state.
*
* @param {Function} onInsert function called when inserter a list of blocks.
* @param {Function} onInsert function called when inserter a list of blocks.
* @param {string=} rootClientId Insertion's root client ID.
*
* @return {Array} Returns the patterns state. (patterns, categories, onSelect handler)
*/
const usePatternsState = ( onInsert ) => {
const { patternCategories, patterns } = useSelect( ( select ) => {
const {
__experimentalBlockPatterns,
__experimentalBlockPatternCategories,
} = select( blockEditorStore ).getSettings();
return {
patterns: __experimentalBlockPatterns,
patternCategories: __experimentalBlockPatternCategories,
};
}, [] );
const usePatternsState = ( onInsert, rootClientId ) => {
const { patternCategories, patterns } = useSelect(
( select ) => {
const { __experimentalGetAllowedPatterns, getSettings } = select(
blockEditorStore
);
return {
patterns: __experimentalGetAllowedPatterns( rootClientId ),
patternCategories: getSettings()
.__experimentalBlockPatternCategories,
};
},
[ rootClientId ]
);
const { createSuccessNotice } = useDispatch( noticesStore );
const onClickPattern = useCallback( ( pattern, blocks ) => {
onInsert(
Expand Down
37 changes: 24 additions & 13 deletions packages/block-editor/src/components/inserter/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,24 @@ function InserterMenu( {
selectBlockOnInsert: __experimentalSelectBlockOnInsert,
insertionIndex: __experimentalInsertionIndex,
} );
const { hasPatterns, hasReusableBlocks } = useSelect( ( select ) => {
const {
__experimentalBlockPatterns,
__experimentalReusableBlocks,
} = select( blockEditorStore ).getSettings();
const { showPatterns, hasReusableBlocks } = useSelect(
( select ) => {
const { __experimentalGetAllowedPatterns, getSettings } = select(
blockEditorStore
);

return {
hasPatterns: !! __experimentalBlockPatterns?.length,
hasReusableBlocks: !! __experimentalReusableBlocks?.length,
};
}, [] );

const showPatterns = ! destinationRootClientId && hasPatterns;
return {
showPatterns:
! destinationRootClientId ||
!! __experimentalGetAllowedPatterns(
destinationRootClientId
).length,
hasReusableBlocks: !! getSettings().__experimentalReusableBlocks
?.length,
};
},
[ destinationRootClientId ]
);

const onInsert = useCallback(
( blocks ) => {
Expand Down Expand Up @@ -126,12 +131,18 @@ function InserterMenu( {
const patternsTab = useMemo(
() => (
<BlockPatternsTabs
rootClientId={ destinationRootClientId }
onInsert={ onInsertPattern }
onClickCategory={ onClickPatternCategory }
selectedCategory={ selectedPatternCategory }
/>
),
[ onInsertPattern, onClickPatternCategory, selectedPatternCategory ]
[
destinationRootClientId,
onInsertPattern,
onClickPatternCategory,
selectedPatternCategory,
]
);

const reusableBlocksTab = useMemo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ export default function QuickInserter( {
onInsertBlocks
);

const [ patterns ] = usePatternsState( onInsertBlocks );
const showPatterns =
! destinationRootClientId && patterns.length && !! filterValue;
const [ patterns ] = usePatternsState(
onInsertBlocks,
destinationRootClientId
);
const showPatterns = patterns.length && !! filterValue;
const showSearch =
( showPatterns && patterns.length > SEARCH_THRESHOLD ) ||
blockTypes.length > SEARCH_THRESHOLD;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ function InserterSearchResults( {
onSelectBlockType,
] = useBlockTypesState( destinationRootClientId, onInsertBlocks );
const [ patterns, , onSelectBlockPattern ] = usePatternsState(
onInsertBlocks
onInsertBlocks,
destinationRootClientId
);

const filteredBlockTypes = useMemo( () => {
Expand Down
45 changes: 45 additions & 0 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
filter,
mapKeys,
orderBy,
every,
} from 'lodash';
import createSelector from 'rememo';

Expand Down Expand Up @@ -1741,6 +1742,50 @@ export const __experimentalGetAllowedBlocks = createSelector(
]
);

const __experimentalGetParsedPatterns = createSelector(
( state ) => {
const patterns = state.settings.__experimentalBlockPatterns;
return map( patterns, ( pattern ) => ( {
...pattern,
contentBlocks: parse( pattern.content ),
} ) );
},
( state ) => [ state.settings.__experimentalBlockPatterns ]
);

/**
* Returns the list of allowed patterns for inner blocks children
*
* @param {Object} state Editor state.
* @param {?string} rootClientId Optional target root client ID.
*
* @return {Array?} The list of allowed block types.
*/
export const __experimentalGetAllowedPatterns = createSelector(
( state, rootClientId = null ) => {
const patterns = __experimentalGetParsedPatterns( state );

if ( ! rootClientId ) {
return patterns;
}

const patternsAllowed = filter( patterns, ( { contentBlocks } ) => {
return every( contentBlocks, ( { name } ) =>
canInsertBlockType( state, name, rootClientId )
);
} );

return patternsAllowed;
},
( state, rootClientId ) => [
state.settings.__experimentalBlockPatterns,
state.settings.allowedBlockTypes,
state.settings.templateLock,
state.blockListSettings[ rootClientId ],
state.blocks.byClientId[ rootClientId ],
]
);

/**
* Returns the Block List settings of a block, if any exist.
*
Expand Down
53 changes: 53 additions & 0 deletions packages/block-editor/src/store/test/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const {
getLowestCommonAncestorWithSelectedBlock,
__experimentalGetActiveBlockIdByBlockNames: getActiveBlockIdByBlockNames,
__experimentalGetParsedReusableBlock,
__experimentalGetAllowedPatterns,
} = selectors;

describe( 'selectors', () => {
Expand Down Expand Up @@ -3349,6 +3350,58 @@ describe( 'selectors', () => {
).toEqual( 'client-id-03' );
} );
} );

describe( '__experimentalGetAllowedPatterns', () => {
const state = {
blocks: {
byClientId: {
block1: { name: 'core/test-block-a' },
block2: { name: 'core/test-block-b' },
},
attributes: {
block1: {},
block2: {},
},
},
blockListSettings: {
block1: {
allowedBlocks: [ 'core/test-block-b' ],
},
block2: {
allowedBlocks: [],
},
},
settings: {
__experimentalBlockPatterns: [
{
title: 'pattern with a',
content: `<!-- wp:test-block-a --><!-- /wp:test-block-a -->`,
},
{
title: 'pattern with b',
content:
'<!-- wp:test-block-b --><!-- /wp:test-block-b -->',
},
],
},
};

it( 'should return all patterns for root level', () => {
expect(
__experimentalGetAllowedPatterns( state, null )
).toHaveLength( 2 );
} );

it( 'should return patterns that consists of blocks allowed for the specified client ID', () => {
expect(
__experimentalGetAllowedPatterns( state, 'block1' )
).toHaveLength( 1 );

expect(
__experimentalGetAllowedPatterns( state, 'block2' )
).toHaveLength( 0 );
} );
} );
} );

describe( '__experimentalGetParsedReusableBlock', () => {
Expand Down
4 changes: 4 additions & 0 deletions packages/edit-post/src/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ function Editor( {
const isFSETheme = getEditorSettings().isFSETheme;
const isViewable = getPostType( postType )?.viewable ?? false;

// Prefetch and parse patterns. This ensures patterns are loaded and parsed when
// the editor is loaded rather than degrading the performance of the inserter.
select( 'core/block-editor' ).__experimentalGetAllowedPatterns();

return {
hasFixedToolbar:
isFeatureActive( 'fixedToolbar' ) ||
Expand Down
4 changes: 4 additions & 0 deletions packages/edit-site/src/components/editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ function Editor( { initialSettings } ) {
const postType = getEditedPostType();
const postId = getEditedPostId();

// Prefetch and parse patterns. This ensures patterns are loaded and parsed when
// the editor is loaded rather than degrading the performance of the inserter.
select( 'core/block-editor' ).__experimentalGetAllowedPatterns();

// The currently selected entity to display. Typically template or template part.
return {
isInserterOpen: isInserterOpened(),
Expand Down

0 comments on commit 6d3c4b3

Please sign in to comment.