Skip to content
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
24 changes: 21 additions & 3 deletions packages/block-editor/src/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1870,9 +1870,27 @@ export function preferences( state = PREFERENCES_DEFAULTS, action ) {
*/
export const blockListSettings = ( state = {}, action ) => {
switch ( action.type ) {
// Even if the replaced blocks have the same client ID, our logic
// should correct the state.
case 'REPLACE_BLOCKS':
case 'REPLACE_BLOCKS': {
// Collect all clientIds from replacement blocks. If a clientId
// is reused, preserve its settings — the block instance (and
// its InnerBlocks config) survived the replace. Settings for
// clientIds that are truly removed get cleaned up so stale
// config from old block types doesn't linger.
const replacementIds = new Set();
const stack = [ ...action.blocks ];
while ( stack.length ) {
const block = stack.shift();
replacementIds.add( block.clientId );
stack.push( ...block.innerBlocks );
}
return Object.fromEntries(
Object.entries( state ).filter(
( [ id ] ) =>
! action.clientIds.includes( id ) ||
replacementIds.has( id )
)
);
}
case 'REMOVE_BLOCKS': {
return Object.fromEntries(
Object.entries( state ).filter(
Expand Down
32 changes: 32 additions & 0 deletions packages/block-editor/src/store/test/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3291,6 +3291,7 @@ describe( 'state', () => {
const state = blockListSettings( original, {
type: 'REPLACE_BLOCKS',
clientIds: [ 'afd1cb17-2c08-4e7a-91be-007ba7ddc3a1' ],
blocks: [],
} );

expect( state ).toEqual( {
Expand All @@ -3300,6 +3301,37 @@ describe( 'state', () => {
} );
} );

it( 'should preserve the settings of a block when its clientId is reused in replacement', () => {
const original = deepFreeze( {
'9db792c6-a25a-495d-adbd-97d56a4c4189': {
allowedBlocks: [ 'core/paragraph' ],
},
'afd1cb17-2c08-4e7a-91be-007ba7ddc3a1': {
allowedBlocks: true,
},
} );

const state = blockListSettings( original, {
type: 'REPLACE_BLOCKS',
clientIds: [ 'afd1cb17-2c08-4e7a-91be-007ba7ddc3a1' ],
blocks: [
{
clientId: 'afd1cb17-2c08-4e7a-91be-007ba7ddc3a1',
innerBlocks: [],
},
],
} );

expect( state ).toEqual( {
'9db792c6-a25a-495d-adbd-97d56a4c4189': {
allowedBlocks: [ 'core/paragraph' ],
},
'afd1cb17-2c08-4e7a-91be-007ba7ddc3a1': {
allowedBlocks: true,
},
} );
} );

it( 'should remove the settings of a block when it is removed', () => {
const original = deepFreeze( {
'afd1cb17-2c08-4e7a-91be-007ba7ddc3a1': {
Expand Down
62 changes: 62 additions & 0 deletions test/e2e/specs/editor/blocks/list.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1656,6 +1656,68 @@ test.describe( 'List (@firefox)', () => {
] );
} );

test( 'should leave the rest of the list intact when merging into an empty list item', async ( {
editor,
page,
} ) => {
await editor.insertBlock( {
name: 'core/list',
innerBlocks: [
{
name: 'core/list-item',
attributes: { content: '1' },
innerBlocks: [
{
name: 'core/list',
innerBlocks: [
{
name: 'core/list-item',
attributes: { content: 'a' },
},
{
name: 'core/list-item',
attributes: { content: 'b' },
},
],
},
],
},
],
} );

await page.keyboard.press( 'ArrowDown' );
await page.keyboard.press( 'ArrowDown' );
await page.keyboard.press( 'Enter' );
await page.keyboard.press( 'Backspace' );

expect( await editor.getBlocks() ).toMatchObject( [
{
name: 'core/list',
innerBlocks: [
{
name: 'core/list-item',
attributes: { content: '1' },
innerBlocks: [
{
name: 'core/list',
innerBlocks: [
{
name: 'core/list-item',
attributes: { content: 'a' },
},
{
name: 'core/list-item',
attributes: { content: 'b' },
},
],
},
],
},
],
},
] );
} );

test( 'should select the list wrapper with select all in empty list item', async ( {
editor,
page,
Expand Down
Loading