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

Inserter: Always show the list of all patterns in the inserter #65611

Merged
merged 3 commits into from
Sep 24, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,66 @@ import { store as noticesStore } from '@wordpress/notices';
* Internal dependencies
*/
import { store as blockEditorStore } from '../../../store';
import { unlock } from '../../../lock-unlock';
import { INSERTER_PATTERN_TYPES } from '../block-patterns-tab/utils';
import { getParsedPattern } from '../../../store/utils';

/**
* Retrieves the block patterns inserter state.
*
* @param {Function} onInsert function called when inserter a list of blocks.
* @param {string=} rootClientId Insertion's root client ID.
*
* @param {string} selectedCategory The selected pattern category.
* @param {boolean} isQuick For the quick inserter render only allowed patterns.
*
* @return {Array} Returns the patterns state. (patterns, categories, onSelect handler)
*/
const usePatternsState = ( onInsert, rootClientId, selectedCategory ) => {
const { patternCategories, patterns, userPatternCategories } = useSelect(
const usePatternsState = (
onInsert,
rootClientId,
selectedCategory,
isQuick
) => {
const { patternCategories, allPatterns, userPatternCategories } = useSelect(
( select ) => {
const { __experimentalGetAllowedPatterns, getSettings } =
select( blockEditorStore );
const {
getAllPatterns,
getSettings,
__experimentalGetAllowedPatterns,
} = unlock( select( blockEditorStore ) );
const {
__experimentalUserPatternCategories,
__experimentalBlockPatternCategories,
} = getSettings();
return {
patterns: __experimentalGetAllowedPatterns( rootClientId ),
allPatterns: isQuick
? __experimentalGetAllowedPatterns()
: getAllPatterns(),
userPatternCategories: __experimentalUserPatternCategories,
patternCategories: __experimentalBlockPatternCategories,
};
},
[ rootClientId ]
[ isQuick ]
);
const { getClosestAllowedInsertionPointForPattern } = unlock(
useSelect( blockEditorStore )
);

const patterns = useMemo(
() =>
isQuick
? allPatterns
: allPatterns
.filter( ( { inserter = true } ) => !! inserter )
.map( ( pattern ) => {
return {
...pattern,
get blocks() {
return getParsedPattern( pattern ).blocks;
},
};
} ),
[ isQuick, allPatterns ]
);

const allCategories = useMemo( () => {
Expand All @@ -58,6 +91,15 @@ const usePatternsState = ( onInsert, rootClientId, selectedCategory ) => {
const { createSuccessNotice } = useDispatch( noticesStore );
const onClickPattern = useCallback(
( pattern, blocks ) => {
const destinationRootClientId = isQuick
? rootClientId
: getClosestAllowedInsertionPointForPattern(
pattern,
rootClientId
);
if ( destinationRootClientId === null ) {
return;
}
const patternBlocks =
pattern.type === INSERTER_PATTERN_TYPES.user &&
pattern.syncStatus !== 'unsynced'
Expand All @@ -77,7 +119,9 @@ const usePatternsState = ( onInsert, rootClientId, selectedCategory ) => {
}
return clonedBlock;
} ),
pattern.name
pattern.name,
false,
destinationRootClientId
);
createSuccessNotice(
sprintf(
Expand All @@ -91,7 +135,14 @@ const usePatternsState = ( onInsert, rootClientId, selectedCategory ) => {
}
);
},
[ createSuccessNotice, onInsert, selectedCategory ]
[
createSuccessNotice,
onInsert,
selectedCategory,
rootClientId,
getClosestAllowedInsertionPointForPattern,
isQuick,
]
);

return [ patterns, allCategories, onClickPattern ];
Expand Down
4 changes: 2 additions & 2 deletions packages/block-editor/src/components/inserter/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,9 @@ function InserterMenu(
);

const onInsertPattern = useCallback(
( blocks, patternName ) => {
( blocks, patternName, ...args ) => {
onToggleInsertionPoint( false );
onInsertBlocks( blocks, { patternName } );
onInsertBlocks( blocks, { patternName }, ...args );
onSelect();
},
[ onInsertBlocks, onSelect ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ export default function QuickInserter( {
onInsertBlocks,
true
);

const [ patterns ] = usePatternsState(
onInsertBlocks,
destinationRootClientId
destinationRootClientId,
undefined,
true
);

const { setInserterIsOpened, insertionIndex } = useSelect(
Expand Down
35 changes: 29 additions & 6 deletions packages/block-editor/src/store/private-selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -642,24 +642,30 @@ export function isZoomOut( state ) {
/**
* Finds the closest block where the block is allowed to be inserted.
*
* @param {Object} state Editor state.
* @param {string} name Block name.
* @param {string} clientId Default insertion point.
* @param {Object} state Editor state.
* @param {string[] | string} name Block name or names.
* @param {string} clientId Default insertion point.
*
* @return {string} clientID of the closest container when the block name can be inserted.
*/
export function getClosestAllowedInsertionPoint( state, name, clientId = '' ) {
const blockNames = Array.isArray( name ) ? name : [ name ];
const areBlockNamesAllowedInClientId = ( id ) =>
blockNames.every( ( currentName ) =>
canInsertBlockType( state, currentName, id )
);

// If we're trying to insert at the root level and it's not allowed
// Try the section root instead.
if ( ! clientId ) {
if ( canInsertBlockType( state, name, clientId ) ) {
if ( areBlockNamesAllowedInClientId( clientId ) ) {
return clientId;
}

const sectionRootClientId = getSectionRootClientId( state );
if (
sectionRootClientId &&
canInsertBlockType( state, name, sectionRootClientId )
areBlockNamesAllowedInClientId( sectionRootClientId )
) {
return sectionRootClientId;
}
Expand All @@ -668,10 +674,27 @@ export function getClosestAllowedInsertionPoint( state, name, clientId = '' ) {

// Traverse the block tree up until we find a place where we can insert.
let current = clientId;
while ( current !== null && ! canInsertBlockType( state, name, current ) ) {
while ( current !== null && ! areBlockNamesAllowedInClientId( current ) ) {
const parentClientId = getBlockRootClientId( state, current );
current = parentClientId;
}

return current;
}

export function getClosestAllowedInsertionPointForPattern(
state,
pattern,
clientId
) {
const { allowedBlockTypes } = getSettings( state );
const isAllowed = checkAllowListRecursive(
getGrammar( pattern ),
allowedBlockTypes
);
if ( ! isAllowed ) {
return null;
}
const names = getGrammar( pattern ).map( ( { blockName: name } ) => name );
return getClosestAllowedInsertionPoint( state, names, clientId );
}
13 changes: 7 additions & 6 deletions test/e2e/specs/editor/various/allowed-patterns.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ test.describe( 'Allowed Patterns', () => {
);
} );

test( 'should show all patterns when all blocks are allowed', async ( {
admin,
page,
} ) => {
test( 'should show all patterns by default', async ( { admin, page } ) => {
await admin.createNewPost();
await page
.getByRole( 'toolbar', { name: 'Document tools' } )
Expand Down Expand Up @@ -57,7 +54,7 @@ test.describe( 'Allowed Patterns', () => {
);
} );

test( 'should show only allowed patterns', async ( {
test( 'should show all patterns even if not allowed', async ( {
admin,
page,
} ) => {
Expand All @@ -80,7 +77,11 @@ test.describe( 'Allowed Patterns', () => {
page
.getByRole( 'listbox', { name: 'Block patterns' } )
.getByRole( 'option' )
).toHaveText( [ 'Test: Single heading' ] );
).toHaveText( [
'Test: Single heading',
'Test: Single paragraph',
'Test: Paragraph inside group',
] );
} );
} );
} );
Loading