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

Global style changes: refactor output for a more flexible UI and grouping #59055

Merged
merged 4 commits into from
Feb 19, 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 @@ -22,8 +22,8 @@ const translationMap = {
h4: __( 'H4' ),
h5: __( 'H5' ),
h6: __( 'H6' ),
'settings.color': __( 'Color settings' ),
'settings.typography': __( 'Typography settings' ),
'settings.color': __( 'Color' ),
'settings.typography': __( 'Typography' ),
'styles.color': __( 'Colors' ),
'styles.spacing': __( 'Spacing' ),
'styles.typography': __( 'Typography' ),
Expand Down Expand Up @@ -54,12 +54,7 @@ function getTranslation( key ) {
}

if ( keyArray?.[ 0 ] === 'elements' ) {
const elementName = translationMap[ keyArray[ 1 ] ] || keyArray[ 1 ];
return sprintf(
// translators: %s: element name, e.g., heading button, link, caption.
__( '%s element' ),
elementName
);
return translationMap[ keyArray[ 1 ] ] || keyArray[ 1 ];
}

return undefined;
Expand Down Expand Up @@ -114,9 +109,9 @@ function deepCompare( changedObject, originalObject, parentPath = '' ) {
*
* @param {Object} next The changed object to compare.
* @param {Object} previous The original object to compare against.
* @return {string[]} An array of translated changes.
* @return {Array[]} A 2-dimensional array of tuples: [ "group", "translated change" ].
*/
function getGlobalStylesChangelist( next, previous ) {
export function getGlobalStylesChangelist( next, previous ) {
const cacheKey = JSON.stringify( { next, previous } );

if ( globalStylesChangesCache.has( cacheKey ) ) {
Expand Down Expand Up @@ -160,12 +155,12 @@ function getGlobalStylesChangelist( next, previous ) {
const result = [ ...new Set( changedValueTree ) ]
/*
* Translate the keys.
* Remove duplicate or empty translations.
* Remove empty translations.
*/
.reduce( ( acc, curr ) => {
const translation = getTranslation( curr );
if ( translation && ! acc.includes( translation ) ) {
acc.push( translation );
if ( translation ) {
acc.push( [ curr.split( '.' )[ 0 ], translation ] );
}
return acc;
}, [] );
Expand All @@ -176,29 +171,80 @@ function getGlobalStylesChangelist( next, previous ) {
}

/**
* From a getGlobalStylesChangelist() result, returns a truncated array of translated changes.
* Appends a translated string indicating the number of changes that were truncated.
* From a getGlobalStylesChangelist() result, returns an array of translated global styles changes, grouped by type.
* The types are 'blocks', 'elements', 'settings', and 'styles'.
*
* @param {Object} next The changed object to compare.
* @param {Object} previous The original object to compare against.
* @param {{maxResults:number}} options Options. maxResults: results to return before truncating.
* @return {string[]} An array of translated changes.
* @return {string[]} An array of translated changes.
*/
export default function getGlobalStylesChanges( next, previous, options = {} ) {
const changes = getGlobalStylesChangelist( next, previous );
const changesLength = changes.length;
let changeList = getGlobalStylesChangelist( next, previous );
const changesLength = changeList.length;
const { maxResults } = options;

// Truncate to `n` results if necessary.
if ( !! maxResults && changesLength && changesLength > maxResults ) {
const deleteCount = changesLength - maxResults;
const andMoreText = sprintf(
// translators: %d: number of global styles changes that are not displayed in the UI.
_n( '…and %d more change', '…and %d more changes', deleteCount ),
deleteCount
);
changes.splice( maxResults, deleteCount, andMoreText );
if ( changesLength ) {
// Truncate to `n` results if necessary.
if ( !! maxResults && changesLength > maxResults ) {
changeList = changeList.slice( 0, maxResults );
}
return Object.entries(
changeList.reduce( ( acc, curr ) => {
const group = acc[ curr[ 0 ] ] || [];
if ( ! group.includes( curr[ 1 ] ) ) {
acc[ curr[ 0 ] ] = [ ...group, curr[ 1 ] ];
}
return acc;
}, {} )
).map( ( [ key, changeValues ] ) => {
const changeValuesLength = changeValues.length;
const joinedChangesValue = changeValues.join( __( ', ' ) );
switch ( key ) {
case 'blocks': {
return sprintf(
// translators: %2$s: a list of block names separated by a comma.
_n( '%2$s block.', '%2$s blocks.', changeValuesLength ),
ramonjd marked this conversation as resolved.
Show resolved Hide resolved
changeValuesLength,
joinedChangesValue
);
}
case 'elements': {
return sprintf(
// translators: %2$s: a list of element names separated by a comma.
_n(
'%2$s element.',
'%2$s elements.',
ramonjd marked this conversation as resolved.
Show resolved Hide resolved
changeValuesLength
),
changeValuesLength,
joinedChangesValue
);
}
case 'settings': {
return sprintf(
// translators: %s: a list of theme.json setting labels separated by a comma.
__( '%s settings.' ),
ramonjd marked this conversation as resolved.
Show resolved Hide resolved
joinedChangesValue
);
}
case 'styles': {
return sprintf(
// translators: %s: a list of theme.json top-level styles labels separated by a comma.
__( '%s styles.' ),
joinedChangesValue
);
}
default: {
return sprintf(
// translators: %s: a list of global styles changes separated by a comma.
__( '%s.' ),
joinedChangesValue
);
}
}
} );
}

return changes;
return EMPTY_ARRAY;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/**
* Internal dependencies
*/
import getGlobalStylesChanges from '../get-global-styles-changes';
import getGlobalStylesChanges, {
getGlobalStylesChangelist,
} from '../get-global-styles-changes';

/**
* WordPress dependencies
Expand All @@ -12,24 +14,8 @@ import {
getBlockTypes,
} from '@wordpress/blocks';

describe( 'getGlobalStylesChanges', () => {
beforeEach( () => {
registerBlockType( 'core/test-fiori-di-zucca', {
save: () => {},
category: 'text',
title: 'Test pumpkin flowers',
edit: () => {},
} );
} );

afterEach( () => {
getBlockTypes().forEach( ( block ) => {
unregisterBlockType( block.name );
} );
} );

const revision = {
id: 10,
describe( 'getGlobalStylesChanges and utils', () => {
const next = {
styles: {
typography: {
fontSize: 'var(--wp--preset--font-size--potato)',
Expand Down Expand Up @@ -85,11 +71,18 @@ describe( 'getGlobalStylesChanges', () => {
},
],
},
gradients: [
{
name: 'Something something',
gradient:
'linear-gradient(105deg,rgba(6,147,100,1) 0%,rgb(155,81,100) 100%)',
slug: 'something-something',
},
],
},
},
};
const previousRevision = {
id: 9,
const previous = {
styles: {
typography: {
fontSize: 'var(--wp--preset--font-size--fungus)',
Expand Down Expand Up @@ -161,74 +154,120 @@ describe( 'getGlobalStylesChanges', () => {
color: 'blue',
},
],
custom: [
{
slug: 'one',
color: 'tomato',
},
],
},
gradients: [
{
name: 'Vivid cyan blue to vivid purple',
gradient:
'linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)',
slug: 'vivid-cyan-blue-to-vivid-purple',
},
],
},
typography: {
fluid: true,
},
},
};

it( 'returns a list of changes and caches them', () => {
const resultA = getGlobalStylesChanges( revision, previousRevision );
expect( resultA ).toEqual( [
'Colors',
'Typography',
'Test pumpkin flowers',
'H3 element',
'Caption element',
'H6 element',
'Link element',
'Color settings',
] );

const resultB = getGlobalStylesChanges( revision, previousRevision );

expect( resultA ).toBe( resultB );
beforeEach( () => {
registerBlockType( 'core/test-fiori-di-zucca', {
save: () => {},
category: 'text',
title: 'Test pumpkin flowers',
edit: () => {},
} );
} );

it( 'returns a list of truncated changes', () => {
const resultA = getGlobalStylesChanges( revision, previousRevision, {
maxResults: 3,
afterEach( () => {
getBlockTypes().forEach( ( block ) => {
unregisterBlockType( block.name );
} );
expect( resultA ).toEqual( [
'Colors',
'Typography',
'Test pumpkin flowers',
'…and 5 more changes',
] );
} );

it( 'skips unknown and unchanged keys', () => {
const result = getGlobalStylesChanges(
{
styles: {
frogs: {
legs: 'green',
},
typography: {
fontSize: '1rem',
},
settings: {
'': {
'': 'foo',
describe( 'getGlobalStylesChanges()', () => {
it( 'returns a list of changes', () => {
const result = getGlobalStylesChanges( next, previous );
expect( result ).toEqual( [
'Colors, Typography styles.',
'Test pumpkin flowers block.',
'H3, Caption, H6, Link elements.',
'Color, Typography settings.',
] );
} );

it( 'returns a list of truncated changes', () => {
const resultA = getGlobalStylesChanges( next, previous, {
maxResults: 3,
} );
expect( resultA ).toEqual( [
'Colors, Typography styles.',
'Test pumpkin flowers block.',
] );
} );

it( 'skips unknown and unchanged keys', () => {
const result = getGlobalStylesChanges(
{
styles: {
frogs: {
legs: 'green',
},
typography: {
fontSize: '1rem',
},
settings: {
'': {
'': 'foo',
},
},
},
},
},
{
styles: {
frogs: {
legs: 'yellow',
},
typography: {
fontSize: '1rem',
},
settings: {
'': {
'': 'bar',
{
styles: {
frogs: {
legs: 'yellow',
},
typography: {
fontSize: '1rem',
},
settings: {
'': {
'': 'bar',
},
},
},
},
}
);
expect( result ).toEqual( [] );
}
);
expect( result ).toEqual( [] );
} );
} );

describe( 'getGlobalStylesChangelist()', () => {
it( 'compares two objects and returns a cached list of changed keys', () => {
const resultA = getGlobalStylesChangelist( next, previous );

expect( resultA ).toEqual( [
[ 'styles', 'Colors' ],
[ 'styles', 'Typography' ],
[ 'blocks', 'Test pumpkin flowers' ],
[ 'elements', 'H3' ],
[ 'elements', 'Caption' ],
[ 'elements', 'H6' ],
[ 'elements', 'Link' ],
[ 'settings', 'Color' ],
[ 'settings', 'Typography' ],
] );

const resultB = getGlobalStylesChangelist( next, previous );

expect( resultB ).toEqual( resultA );
} );
} );
} );
Loading
Loading