diff --git a/packages/editor/src/hooks/custom-class-name.js b/packages/editor/src/hooks/custom-class-name.js index 8cde23572ea7a1..c69143fda71936 100644 --- a/packages/editor/src/hooks/custom-class-name.js +++ b/packages/editor/src/hooks/custom-class-name.js @@ -136,15 +136,21 @@ export function addParsedDifference( blockAttributes, blockType, innerHTML ) { // To determine difference, serialize block given the known set of // attributes. If there are classes which are mismatched with the // incoming HTML of the block, add to filtered result. + // If existing classes have been removed then ensure they don't appear in the output const serialized = getSaveContent( blockType, blockAttributes ); + const blockClasses = blockAttributes.className ? blockAttributes.className.split( ' ' ) : []; const classes = getHTMLRootElementClasses( serialized ); const parsedClasses = getHTMLRootElementClasses( innerHTML ); const customClasses = difference( parsedClasses, classes ); - const filteredClassName = compact( [ - blockAttributes.className, + // The remaining classes consist of the block's current classes (with default classes removed if they don't already exist in the block) + // along with any custom classes, removing any class that doesn't appear in the innerHTML + const remaining = [ + ...classes.filter( ( item ) => blockClasses.indexOf( item ) !== -1 ), ...customClasses, - ] ).join( ' ' ); + ].filter( ( item ) => parsedClasses.indexOf( item ) !== -1 ); + + const filteredClassName = compact( remaining ).join( ' ' ); if ( filteredClassName ) { blockAttributes.className = filteredClassName; diff --git a/packages/editor/src/hooks/test/custom-class-name.js b/packages/editor/src/hooks/test/custom-class-name.js index 3414889aff7c5e..c7f1b3e1c1c5c5 100644 --- a/packages/editor/src/hooks/test/custom-class-name.js +++ b/packages/editor/src/hooks/test/custom-class-name.js @@ -110,5 +110,45 @@ describe( 'custom className', () => { expect( attributes.className ).toBeUndefined(); } ); + + it( 'should add a custom class name to an element without a class', () => { + const attributes = addParsedDifference( + {}, + blockSettings, + '
' + ); + + expect( attributes.className ).toBe( 'foo' ); + } ); + + it( 'should remove the custom class and retain default class', () => { + const attributes = addParsedDifference( + { className: 'default custom' }, + blockSettings, + '
' + ); + + expect( attributes.className ).toBe( 'default' ); + } ); + + it( 'should remove the custom class from an element originally without a class', () => { + const attributes = addParsedDifference( + { className: 'foo' }, + blockSettings, + '
' + ); + + expect( attributes.className ).toBeUndefined(); + } ); + + it( 'should remove the custom classes and retain default and other custom class', () => { + const attributes = addParsedDifference( + { className: 'default custom1 custom2 custom3' }, + blockSettings, + '
' + ); + + expect( attributes.className ).toBe( 'default custom1 custom3' ); + } ); } ); } );