diff --git a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js index e695a845ff50..7d83b08424d7 100644 --- a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js @@ -2698,5 +2698,34 @@ describe('ReactDOMComponent', () => { ReactDOM.render(, container); expect(typeof container.onclick).not.toBe('function'); }); + + it('should warn about css shorthand properties collision', () => { + const container = document.createElement('div'); + const oldStyle = { + background: 'url(http://example.org/image/a.jpg) no-repeat center', + backgroundSize: '150px', + backgroundColor: 'red', + }; + + ReactDOM.render(
, container); + const stubStyle = container.firstChild.style; + + expect(stubStyle.background).toEqual( + 'url(http://example.org/image/a.jpg) no-repeat center', + ); + expect(stubStyle.backgroundSize).toEqual('150px'); + expect(stubStyle.backgroundColor).toEqual('red'); + + const newStyle = { + background: 'url(http://example.org/image/b.jpg) no-repeat center', + }; + + expect(() => + ReactDOM.render(
, container), + ).toWarnDev( + 'Warning: Css shorthand properties collision:' + + ' background properties are being overridden. (backgroundSize,backgroundColor)', + ); + }); }); }); diff --git a/packages/react-dom/src/client/ReactDOMComponent.js b/packages/react-dom/src/client/ReactDOMComponent.js index 4fded23f31a7..7b61931c5d2b 100644 --- a/packages/react-dom/src/client/ReactDOMComponent.js +++ b/packages/react-dom/src/client/ReactDOMComponent.js @@ -13,6 +13,7 @@ import {registrationNameModules} from 'events/EventPluginRegistry'; import warning from 'shared/warning'; import {canUseDOM} from 'shared/ExecutionEnvironment'; import warningWithoutStack from 'shared/warningWithoutStack'; +import {shorthandProperties} from '../shared/CSSProperty'; import * as DOMPropertyOperations from './DOMPropertyOperations'; import * as ReactDOMInput from './ReactDOMInput'; @@ -709,6 +710,26 @@ export function diffProperties( if (!styleUpdates) { styleUpdates = {}; } + // Check shorthand properties collision + if (__DEV__) { + if (shorthandProperties.hasOwnProperty(styleName)) { + const propertyGroup = shorthandProperties[styleName]; + const overriddenProperties = []; + for (let lastStyleName in lastProp) { + if (propertyGroup.includes(lastStyleName)) { + overriddenProperties.push(lastStyleName); + } + } + if (overriddenProperties.length > 0) { + warning( + false, + 'Css shorthand properties collision: %s properties are being overridden. (%s)', + styleName, + overriddenProperties, + ); + } + } + } styleUpdates[styleName] = nextProp[styleName]; } } diff --git a/packages/react-dom/src/shared/CSSProperty.js b/packages/react-dom/src/shared/CSSProperty.js index 7b1e4aba8b54..3590478443ef 100644 --- a/packages/react-dom/src/shared/CSSProperty.js +++ b/packages/react-dom/src/shared/CSSProperty.js @@ -55,6 +55,18 @@ export const isUnitlessNumber = { strokeWidth: true, }; +export const shorthandProperties = { + background: [ + 'backgroundAttachment', + 'backgroundClip', + 'backgroundColor', + 'backgroundImage', + 'backgroundOrigin', + 'backgroundPosition', + 'backgroundRepeat', + 'backgroundSize', + ], +}; /** * @param {string} prefix vendor-specific prefix, eg: Webkit * @param {string} key style name, eg: transitionDuration