From f12e276f251416f020ef7bb4795e81f2ce39b79d Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 29 Oct 2020 00:01:08 +0100 Subject: [PATCH] add ability to merge arrays of objects when using extend --- __tests__/resolveConfig.test.js | 72 ++++++++++++++++++++++++++++++++- src/util/resolveConfig.js | 22 +++++++++- 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/__tests__/resolveConfig.test.js b/__tests__/resolveConfig.test.js index e7a728d6922d..b36f8c8c0149 100644 --- a/__tests__/resolveConfig.test.js +++ b/__tests__/resolveConfig.test.js @@ -810,7 +810,7 @@ test('theme values in the extend section can extend values that are depended on }) }) -test('theme values in the extend section are not deeply merged', () => { +test('theme values in the extend section are not deeply merged when they are simple arrays', () => { const userConfig = { theme: { extend: { @@ -856,6 +856,76 @@ test('theme values in the extend section are not deeply merged', () => { }) }) +test('theme values in the extend section are deeply merged, when they are arrays of objects', () => { + const userConfig = { + theme: { + extend: { + typography: { + ArrayArray: { + css: [{ a: { backgroundColor: 'red' } }, { a: { color: 'green' } }], + }, + ObjectArray: { + css: { a: { backgroundColor: 'red' } }, + }, + ArrayObject: { + css: [{ a: { backgroundColor: 'red' } }, { a: { color: 'green' } }], + }, + }, + }, + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + theme: { + typography: { + ArrayArray: { + css: [{ a: { underline: 'none' } }], + }, + ObjectArray: { + css: [{ a: { underline: 'none' } }], + }, + ArrayObject: { + css: { a: { underline: 'none' } }, + }, + }, + }, + variants: {}, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + typography: { + ArrayArray: { + css: [ + { a: { underline: 'none' } }, + { a: { backgroundColor: 'red' } }, + { a: { color: 'green' } }, + ], + }, + ObjectArray: { + css: [{ a: { underline: 'none' } }, { a: { backgroundColor: 'red' } }], + }, + ArrayObject: { + css: [ + { a: { underline: 'none' } }, + { a: { backgroundColor: 'red' } }, + { a: { color: 'green' } }, + ], + }, + }, + }, + variants: {}, + }) +}) + test('the theme function can use a default value if the key is missing', () => { const userConfig = { theme: { diff --git a/src/util/resolveConfig.js b/src/util/resolveConfig.js index 7b6c9c447811..774512fdb448 100644 --- a/src/util/resolveConfig.js +++ b/src/util/resolveConfig.js @@ -7,6 +7,8 @@ import map from 'lodash/map' import get from 'lodash/get' import uniq from 'lodash/uniq' import toPath from 'lodash/toPath' +import head from 'lodash/head' +import isPlainObject from 'lodash/isPlainObject' import negateValue from './negateValue' import { corePluginList } from '../corePluginList' import configurePlugins from './configurePlugins' @@ -67,8 +69,24 @@ function mergeThemes(themes) { } } -function mergeExtensionCustomizer(_merged, value) { - if (Array.isArray(value)) return value +function mergeExtensionCustomizer(merged, value) { + // When we have an array of objects, we do want to merge it + if (Array.isArray(merged) && isPlainObject(head(merged))) { + return merged.concat(value) + } + + // When the incoming value is an array, and the existing config is an object, prepend the existing object + if (Array.isArray(value) && isPlainObject(head(value)) && isPlainObject(merged)) { + return [merged, ...value] + } + + // Override arrays (for example for font-families, box-shadows, ...) + if (Array.isArray(value)) { + return value + } + + // Execute default behaviour + return undefined } function mergeExtensions({ extend, ...theme }) {