UNPKG

@wordpress/block-editor

Version:
232 lines (222 loc) 8.18 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getGlobalStylesChanges; exports.getGlobalStylesChangelist = getGlobalStylesChangelist; var _memize = _interopRequireDefault(require("memize")); var _i18n = require("@wordpress/i18n"); var _blocks = require("@wordpress/blocks"); /** * External dependencies */ /** * WordPress dependencies */ const globalStylesChangesCache = new Map(); const EMPTY_ARRAY = []; const translationMap = { caption: (0, _i18n.__)('Caption'), link: (0, _i18n.__)('Link'), button: (0, _i18n.__)('Button'), heading: (0, _i18n.__)('Heading'), h1: (0, _i18n.__)('H1'), h2: (0, _i18n.__)('H2'), h3: (0, _i18n.__)('H3'), h4: (0, _i18n.__)('H4'), h5: (0, _i18n.__)('H5'), h6: (0, _i18n.__)('H6'), 'settings.color': (0, _i18n.__)('Color'), 'settings.typography': (0, _i18n.__)('Typography'), 'styles.color': (0, _i18n.__)('Colors'), 'styles.spacing': (0, _i18n.__)('Spacing'), 'styles.background': (0, _i18n.__)('Background'), 'styles.typography': (0, _i18n.__)('Typography') }; const getBlockNames = (0, _memize.default)(() => (0, _blocks.getBlockTypes)().reduce((accumulator, { name, title }) => { accumulator[name] = title; return accumulator; }, {})); const isObject = obj => obj !== null && typeof obj === 'object'; /** * Get the translation for a given global styles key. * @param {string} key A key representing a path to a global style property or setting. * @return {string|undefined} A translated key or undefined if no translation exists. */ function getTranslation(key) { if (translationMap[key]) { return translationMap[key]; } const keyArray = key.split('.'); if (keyArray?.[0] === 'blocks') { const blockName = getBlockNames()?.[keyArray[1]]; return blockName || keyArray[1]; } if (keyArray?.[0] === 'elements') { return translationMap[keyArray[1]] || keyArray[1]; } return undefined; } /** * A deep comparison of two objects, optimized for comparing global styles. * @param {Object} changedObject The changed object to compare. * @param {Object} originalObject The original object to compare against. * @param {string} parentPath A key/value pair object of block names and their rendered titles. * @return {string[]} An array of paths whose values have changed. */ function deepCompare(changedObject, originalObject, parentPath = '') { // We have two non-object values to compare. if (!isObject(changedObject) && !isObject(originalObject)) { /* * Only return a path if the value has changed. * And then only the path name up to 2 levels deep. */ return changedObject !== originalObject ? parentPath.split('.').slice(0, 2).join('.') : undefined; } // Enable comparison when an object doesn't have a corresponding property to compare. changedObject = isObject(changedObject) ? changedObject : {}; originalObject = isObject(originalObject) ? originalObject : {}; const allKeys = new Set([...Object.keys(changedObject), ...Object.keys(originalObject)]); let diffs = []; for (const key of allKeys) { const path = parentPath ? parentPath + '.' + key : key; const changedPath = deepCompare(changedObject[key], originalObject[key], path); if (changedPath) { diffs = diffs.concat(changedPath); } } return diffs; } /** * Returns an array of translated summarized global styles changes. * Results are cached using a Map() key of `JSON.stringify( { next, previous } )`. * * @param {Object} next The changed object to compare. * @param {Object} previous The original object to compare against. * @return {Array[]} A 2-dimensional array of tuples: [ "group", "translated change" ]. */ function getGlobalStylesChangelist(next, previous) { const cacheKey = JSON.stringify({ next, previous }); if (globalStylesChangesCache.has(cacheKey)) { return globalStylesChangesCache.get(cacheKey); } /* * Compare the two changesets with normalized keys. * The order of these keys determines the order in which * they'll appear in the results. */ const changedValueTree = deepCompare({ styles: { background: next?.styles?.background, color: next?.styles?.color, typography: next?.styles?.typography, spacing: next?.styles?.spacing }, blocks: next?.styles?.blocks, elements: next?.styles?.elements, settings: next?.settings }, { styles: { background: previous?.styles?.background, color: previous?.styles?.color, typography: previous?.styles?.typography, spacing: previous?.styles?.spacing }, blocks: previous?.styles?.blocks, elements: previous?.styles?.elements, settings: previous?.settings }); if (!changedValueTree.length) { globalStylesChangesCache.set(cacheKey, EMPTY_ARRAY); return EMPTY_ARRAY; } // Remove duplicate results. const result = [...new Set(changedValueTree)] /* * Translate the keys. * Remove empty translations. */.reduce((acc, curr) => { const translation = getTranslation(curr); if (translation) { acc.push([curr.split('.')[0], translation]); } return acc; }, []); globalStylesChangesCache.set(cacheKey, result); return result; } /** * 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. */ function getGlobalStylesChanges(next, previous, options = {}) { let changeList = getGlobalStylesChangelist(next, previous); const changesLength = changeList.length; const { maxResults } = options; 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(/* translators: Used between list items, there is a space after the comma. */ (0, _i18n.__)(', ') // eslint-disable-line @wordpress/i18n-no-flanking-whitespace ); switch (key) { case 'blocks': { return (0, _i18n.sprintf)( // translators: %s: a list of block names separated by a comma. (0, _i18n._n)('%s block.', '%s blocks.', changeValuesLength), joinedChangesValue); } case 'elements': { return (0, _i18n.sprintf)( // translators: %s: a list of element names separated by a comma. (0, _i18n._n)('%s element.', '%s elements.', changeValuesLength), joinedChangesValue); } case 'settings': { return (0, _i18n.sprintf)( // translators: %s: a list of theme.json setting labels separated by a comma. (0, _i18n.__)('%s settings.'), joinedChangesValue); } case 'styles': { return (0, _i18n.sprintf)( // translators: %s: a list of theme.json top-level styles labels separated by a comma. (0, _i18n.__)('%s styles.'), joinedChangesValue); } default: { return (0, _i18n.sprintf)( // translators: %s: a list of global styles changes separated by a comma. (0, _i18n.__)('%s.'), joinedChangesValue); } } }); } return EMPTY_ARRAY; } //# sourceMappingURL=get-global-styles-changes.js.map