-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Pulling out the utils from #56622 so we test separately
- Loading branch information
Showing
3 changed files
with
134 additions
and
4 deletions.
There are no files selected for viewing
125 changes: 125 additions & 0 deletions
125
packages/edit-site/src/components/global-styles/use-theme-style-variations-by-property.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useSelect } from '@wordpress/data'; | ||
import { store as coreStore } from '@wordpress/core-data'; | ||
import { useContext, useMemo } from '@wordpress/element'; | ||
import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { unlock } from '../../lock-unlock'; | ||
import cloneDeep from '../../utils/clone-deep'; | ||
import { mergeBaseAndUserConfigs } from './global-styles-provider'; | ||
/** | ||
* Returns a new object with only the properties specified in `properties`. | ||
* | ||
* @param {Object} object The object to filter | ||
* @param {Object} property The property to filter by | ||
* @return {Object} The merged object. | ||
*/ | ||
export const filterObjectByProperty = ( object, property ) => { | ||
if ( ! object ) { | ||
return {}; | ||
} | ||
|
||
const newObject = {}; | ||
Object.keys( object ).forEach( ( key ) => { | ||
if ( key === property ) { | ||
newObject[ key ] = object[ key ]; | ||
} else if ( typeof object[ key ] === 'object' ) { | ||
const newFilter = filterObjectByProperty( object[ key ], property ); | ||
if ( Object.keys( newFilter ).length ) { | ||
newObject[ key ] = newFilter; | ||
} | ||
} | ||
} ); | ||
return newObject; | ||
}; | ||
|
||
/** | ||
* Removes all instances of a property from an object. | ||
* | ||
* @param {Object} object | ||
* @param {string} property | ||
* @return {Object} The modified object. | ||
*/ | ||
const removePropertyFromObject = ( object, property ) => { | ||
for ( const key in object ) { | ||
if ( key === property ) { | ||
delete object[ key ]; | ||
} else if ( typeof object[ key ] === 'object' ) { | ||
removePropertyFromObject( object[ key ], property ); | ||
} | ||
} | ||
return object; | ||
}; | ||
|
||
/** | ||
* Return style variations with all properties removed except for the one specified in `type`. | ||
* | ||
* @param {Object} user The user variation. | ||
* @param {Array} variations The other style variations. | ||
* @param {string} property The property to filter by. | ||
* | ||
* @return {Array} The style variation with only the specified property filtered. | ||
*/ | ||
export const getVariationsByProperty = ( user, variations, property ) => { | ||
const userSettingsWithoutProperty = removePropertyFromObject( | ||
cloneDeep( user ), | ||
property | ||
); | ||
|
||
const variationsWithOnlyProperty = variations.map( ( variation ) => { | ||
return { | ||
...filterObjectByProperty( variation, property ), | ||
// Add variation title and description to every variation item. | ||
title: variation?.title, | ||
description: variation?.description, | ||
}; | ||
} ); | ||
|
||
return variationsWithOnlyProperty.map( ( variation ) => | ||
mergeBaseAndUserConfigs( userSettingsWithoutProperty, variation ) | ||
); | ||
}; | ||
|
||
const { GlobalStylesContext } = unlock( blockEditorPrivateApis ); | ||
|
||
export default function useThemeStyleVariationsByProperty( { | ||
styleProperty, | ||
filter, | ||
} ) { | ||
const variations = useSelect( ( select ) => { | ||
return select( | ||
coreStore | ||
).__experimentalGetCurrentThemeGlobalStylesVariations(); | ||
}, [] ); | ||
const { user } = useContext( GlobalStylesContext ); | ||
|
||
return useMemo( () => { | ||
if ( ! styleProperty || ! variations.length ) { | ||
return []; | ||
} | ||
/* | ||
@TODO: | ||
For colors, should also get filter? | ||
Memoize/cache all this better? E.g., should we memoize the variations? | ||
Test with empty theme | ||
Test with 2022 - typography font families bork for some reason | ||
*/ | ||
let styleVariations = getVariationsByProperty( | ||
user, | ||
variations, | ||
styleProperty | ||
); | ||
|
||
if ( 'function' === typeof filter ) { | ||
styleVariations = styleVariations.filter( filter ); | ||
} | ||
|
||
return styleVariations; | ||
}, [ styleProperty, variations, filter ] ); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/** | ||
* Makes a copy of an object without storing any references to the original object. | ||
* @param {Object} object | ||
* @return {Object} The cloned object. | ||
*/ | ||
export default function cloneDeep( object ) { | ||
return ! object ? {} : JSON.parse( JSON.stringify( object ) ); | ||
} |