Skip to content
This repository has been archived by the owner on Feb 12, 2021. It is now read-only.

Commit

Permalink
Merge pull request #59 from klarna/change-with-stylesheet-override
Browse files Browse the repository at this point in the history
Post compose function styles
  • Loading branch information
xaviervia authored Dec 17, 2017
2 parents 56378d1 + e7e7425 commit 478c0b2
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 48 deletions.
52 changes: 43 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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}) {
Expand All @@ -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'
Expand All @@ -56,9 +52,9 @@ render(
<EnhancedTitle
tagline='Hello!'
pressed
getStyleSheet={({hasTagline, pressed}) => ({
getStyleSheet={({tagline, pressed}) => ({
title: {
background: hasTagline ? 'white' : 'pink'
background: tagline && tagline.length > 0 ? 'white' : 'pink'
},
tagline: {
background: pressed ? 'white' : 'pink'
Expand All @@ -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 <header>
<h1 style={styleSheet.title(title)}>{title}</h1>
<p style={styleSheet.tagline}>{tagline}</p>
</header>
}

const EnhancedTitle = withStyleSheetOverride(
({pressed}) => ({
title: text => ({
color: text.length > 30 ? 'red' : 'black'
}),
tagline: {
color: pressed ? 'lightblue' : 'gray'
}
})
)(Header)

render(
<EnhancedTitle
tagline='Hello!'
pressed
getStyleSheet={({pressed}) => ({
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.
Expand Down
31 changes: 23 additions & 8 deletions src/withStyleSheetOverride.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) =>
<Target
styleSheet={deepMerge(
getDefaultStyleSheet(propsSelector(props)),
getStyleSheet(propsSelector(props))
)}
{...props}
/>
<Target styleSheet={merge(getDefaultStyleSheet(props), getStyleSheet(props))} {...props} />
)
91 changes: 60 additions & 31 deletions src/withStyleSheetOverride.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,11 @@ describe('withStyleSheetOverride', () => {
)
}

const Enhanced = withStyleSheetOverride(
x => x,
() => ({
base: {
color: 'red',
},
})
)(Target)
const Enhanced = withStyleSheetOverride(() => ({
base: {
color: 'red',
},
}))(Target)

render(<Enhanced />, root)

Expand All @@ -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(<Enhanced hovered pressed />, root)

Expand All @@ -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(
<Enhanced
hovered
pressed
getStyleSheet={({ hoveredAndPressed }) => ({
getStyleSheet={({ hovered, pressed }) => ({
base: {
background: hoveredAndPressed ? 'rebeccapurple' : 'bisque',
background: hovered && pressed ? 'rebeccapurple' : 'bisque',
},
})}
/>,
Expand All @@ -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 (
<div>
<h1>
{styleSheet.base().color}
</h1>
<p>
{styleSheet.base().background}
</p>
</div>
)
}

const Enhanced = withStyleSheetOverride(({ hovered, pressed }) => ({
base: () => ({
color: hovered && pressed ? 'green' : 'red',
background: 'blue',
}),
}))(Target)

render(
<Enhanced
hovered
pressed
getStyleSheet={({ hovered, pressed }) => ({
base: {
background: hovered && pressed ? 'rebeccapurple' : 'bisque',
},
})}
/>,
root
)

equal(root.querySelector('h1').innerText, 'green')
equal(root.querySelector('p').innerText, 'rebeccapurple')
})
})
})
})

0 comments on commit 478c0b2

Please sign in to comment.