diff --git a/README.md b/README.md index 95023c9..8272d8b 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,9 @@ function MyDiv ({style}) { export default normalizeStyle(MyDiv) ``` -## withStyleSheetOverride (propsSelector, getDefaultStyleSheet) (Component) +## withStyleSheetOverride (getDefaultStyleSheet) (Component) -**withStyleSheetOverride** provides a flexible way of setting style sheets in the components. The first argument to it is a selector from all the `props` to an object of values that are relevant for styles. The second argument is a function from those values to a stylesheet structure. It also provides the ability for consumers of the component to pass their own `getStyleSheet` prop that takes the same subset of the props and returns another style sheet that `withStyleSheetOverride` will deep merge on top of the default ones. For example: +**withStyleSheetOverride** provides a flexible way of setting style sheets in the components. It takes a function from `props` to a stylesheet structure. It also provides the ability for consumers of the component to pass their own `getStyleSheet` prop that takes the props and returns another style sheet: `withStyleSheetOverride` will deep merge this override style sheet on top of the default styles. For example: ```javascript function Header({styleSheet, title, tagline}) { @@ -39,12 +39,8 @@ function Header({styleSheet, title, tagline}) { const EnhancedTitle = withStyleSheetOverride( ({tagline, pressed}) => ({ - hasTagline: tagline && tagline.length > 0, - pressed - }), - ({hasTagline, pressed}) => ({ title: { - color: hasTagline ? 'blue' : 'black' + color: tagline && tagline.length > 0 ? 'blue' : 'black' }, tagline: { color: pressed ? 'lightblue' : 'gray' @@ -56,9 +52,9 @@ render( ({ + getStyleSheet={({tagline, pressed}) => ({ title: { - background: hasTagline ? 'white' : 'pink' + background: tagline && tagline.length > 0 ? 'white' : 'pink' }, tagline: { background: pressed ? 'white' : 'pink' @@ -71,6 +67,44 @@ render( …will render the `h1` with `{ color: 'blue', background: 'white' }` and the `p` with `{ color: 'lightblue', background: 'white' }`. +Functions as styles instead of objects are also supported. This would work as well: + +```javascript +function Header({styleSheet, title, tagline}) { + return
+

{title}

+

{tagline}

+
+} + +const EnhancedTitle = withStyleSheetOverride( + ({pressed}) => ({ + title: text => ({ + color: text.length > 30 ? 'red' : 'black' + }), + tagline: { + color: pressed ? 'lightblue' : 'gray' + } + }) +)(Header) + +render( + ({ + title: text => ({ + background: text.length < 10 ? 'white' : 'pink' + }), + tagline: { + background: pressed ? 'white' : 'pink' + } + })} + />, + document.getElementById('root') +) +``` + ## withDisplayName (string) ... (Component) **withDisplayName** let's you easily set the `displayName` of components. diff --git a/src/withStyleSheetOverride.js b/src/withStyleSheetOverride.js index 21f3508..ee0d9d3 100644 --- a/src/withStyleSheetOverride.js +++ b/src/withStyleSheetOverride.js @@ -4,15 +4,30 @@ import wrapDisplayName from 'recompose/wrapDisplayName' import setDisplayName from 'recompose/setDisplayName' import deepMerge from 'deepmerge' -export default (propsSelector, getDefaultStyleSheet) => Target => +const styleWrapperFunction = (defaultStyle, overrideStyle = {}) => { + if (typeof defaultStyle === 'function') { + return (...args) => + deepMerge( + defaultStyle(...args), + typeof overrideStyle === 'function' ? overrideStyle(...args) : overrideStyle + ) + } else { + return deepMerge(defaultStyle, overrideStyle) + } +} + +const merge = (defaultStyleSheet, overrideStyleSheet = {}) => + Object.keys(defaultStyleSheet).reduce( + (result, key) => ({ + ...result, + [key]: styleWrapperFunction(defaultStyleSheet[key], overrideStyleSheet[key]), + }), + {} + ) + +export default getDefaultStyleSheet => Target => compose( setDisplayName(wrapDisplayName(Target, 'withStyleSheetOverride')) )(({ getStyleSheet = () => ({}), ...props }) => - + ) diff --git a/src/withStyleSheetOverride.spec.js b/src/withStyleSheetOverride.spec.js index 73d568e..bebafe0 100644 --- a/src/withStyleSheetOverride.spec.js +++ b/src/withStyleSheetOverride.spec.js @@ -24,14 +24,11 @@ describe('withStyleSheetOverride', () => { ) } - const Enhanced = withStyleSheetOverride( - x => x, - () => ({ - base: { - color: 'red', - }, - }) - )(Target) + const Enhanced = withStyleSheetOverride(() => ({ + base: { + color: 'red', + }, + }))(Target) render(, root) @@ -49,16 +46,11 @@ describe('withStyleSheetOverride', () => { ) } - const Enhanced = withStyleSheetOverride( - ({ hovered, pressed }) => ({ - hoveredAndPressed: hovered && pressed, - }), - ({ hoveredAndPressed }) => ({ - base: { - color: hoveredAndPressed ? 'green' : 'red', - }, - }) - )(Target) + const Enhanced = withStyleSheetOverride(({ hovered, pressed }) => ({ + base: { + color: hovered && pressed ? 'green' : 'red', + }, + }))(Target) render(, root) @@ -83,25 +75,20 @@ describe('withStyleSheetOverride', () => { ) } - const Enhanced = withStyleSheetOverride( - ({ hovered, pressed }) => ({ - hoveredAndPressed: hovered && pressed, - }), - ({ hoveredAndPressed }) => ({ - base: { - color: hoveredAndPressed ? 'green' : 'red', - background: 'blue', - }, - }) - )(Target) + const Enhanced = withStyleSheetOverride(({ hovered, pressed }) => ({ + base: { + color: hovered && pressed ? 'green' : 'red', + background: 'blue', + }, + }))(Target) render( ({ + getStyleSheet={({ hovered, pressed }) => ({ base: { - background: hoveredAndPressed ? 'rebeccapurple' : 'bisque', + background: hovered && pressed ? 'rebeccapurple' : 'bisque', }, })} />, @@ -111,5 +98,47 @@ describe('withStyleSheetOverride', () => { equal(root.querySelector('h1').innerText, 'green') equal(root.querySelector('p').innerText, 'rebeccapurple') }) + + describe('when the default styles include a function', () => { + it('the styleSheet is a deepmerge of both results', () => { + const root = document.createElement('div') + + function Target({ styleSheet }) { + return ( +
+

+ {styleSheet.base().color} +

+

+ {styleSheet.base().background} +

+
+ ) + } + + const Enhanced = withStyleSheetOverride(({ hovered, pressed }) => ({ + base: () => ({ + color: hovered && pressed ? 'green' : 'red', + background: 'blue', + }), + }))(Target) + + render( + ({ + base: { + background: hovered && pressed ? 'rebeccapurple' : 'bisque', + }, + })} + />, + root + ) + + equal(root.querySelector('h1').innerText, 'green') + equal(root.querySelector('p').innerText, 'rebeccapurple') + }) + }) }) })