Skip to content
This repository has been archived by the owner on Dec 13, 2018. It is now read-only.

Commit

Permalink
feat(filterProps): add option to filter props (#315)
Browse files Browse the repository at this point in the history
* feat(filterProps): add option to filter props (#314)

Allow to filter specific props of a glamorous component to be not
forwarded to its children. Sometimes it may not be possible to set the
rooEl option to filter unknown properties for the leaf elements. This is
especially the case when glamorous is being used within a HOC.

This commit adds a new filterProps option. The option expects an array
of prop names which shouldn't be passed to child components.

* docs: add me to contributors

* Update split-props.js

closes #314
  • Loading branch information
bjoernricks authored and Kent C. Dodds committed Aug 31, 2017
1 parent a027e20 commit a94d620
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 11 deletions.
12 changes: 12 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,18 @@
"code",
"test"
]
},
{
"login": "bjoernricks",
"name": "Björn Ricks",
"avatar_url": "https://avatars2.githubusercontent.com/u/897575?v=4",
"profile": "https://twitter.com/bjoernricks",
"contributions": [
"bug",
"code",
"doc",
"test"
]
}
]
}
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
[![downloads][downloads-badge]][npmcharts]
[![MIT License][license-badge]][LICENSE]

[![All Contributors](https://img.shields.io/badge/all_contributors-50-orange.svg?style=flat-square)](#contributors)
[![All Contributors](https://img.shields.io/badge/all_contributors-51-orange.svg?style=flat-square)](#contributors)
[![PRs Welcome][prs-badge]][prs]
[![Chat][chat-badge]][chat]
[![Code of Conduct][coc-badge]][coc]
Expand Down Expand Up @@ -121,7 +121,7 @@ Thanks goes to these people ([emoji key][emojis]):
| [<img src="https://avatars2.githubusercontent.com/u/4118089?v=3" width="100px;"/><br /><sub>FredericH</sub>](http://fr.linkedin.com/in/fredericheem)<br />[💡](#example-FredericHeem "Examples") | [<img src="https://avatars3.githubusercontent.com/u/656630?v=3" width="100px;"/><br /><sub>Atticus White</sub>](https://atticuswhite.com)<br />[📖](https://github.com/paypal/glamorous/commits?author=ajwhite "Documentation") [🔌](#plugin-ajwhite "Plugin/utility libraries") | [<img src="https://avatars0.githubusercontent.com/u/13483453?v=3" width="100px;"/><br /><sub>marzelin</sub>](https://github.com/marzelin)<br />[💻](https://github.com/paypal/glamorous/commits?author=marzelin "Code") | [<img src="https://avatars2.githubusercontent.com/u/4074973?v=3" width="100px;"/><br /><sub>iwantmyname</sub>](https://iwantmyname.com/)<br />[🚇](#infra-iwantmyname "Infrastructure (Hosting, Build-Tools, etc)") | [<img src="https://avatars1.githubusercontent.com/u/11809142?v=3" width="100px;"/><br /><sub>Ethan Godt</sub>](http://ethangodt.com)<br /> | [<img src="https://avatars3.githubusercontent.com/u/2175447?v=3" width="100px;"/><br /><sub>Zill Ding</sub>](https://github.com/zillding)<br />[💻](https://github.com/paypal/glamorous/commits?author=zillding "Code") | [<img src="https://avatars3.githubusercontent.com/u/411643?v=3" width="100px;"/><br /><sub>Dan Bradley</sub>](https://github.com/debradley)<br />[💻](https://github.com/paypal/glamorous/commits?author=debradley "Code") |
| [<img src="https://avatars3.githubusercontent.com/u/22868432?v=3" width="100px;"/><br /><sub>Lufty Wiranda</sub>](http://instagram.com/luftywiranda13)<br />[💻](https://github.com/paypal/glamorous/commits?author=luftywiranda13 "Code") | [<img src="https://avatars3.githubusercontent.com/u/3208863?v=3" width="100px;"/><br /><sub>Ansuman Shah</sub>](https://github.com/ansumanshah)<br />[💻](https://github.com/paypal/glamorous/commits?author=ansumanshah "Code") [📖](https://github.com/paypal/glamorous/commits?author=ansumanshah "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/11598?v=3" width="100px;"/><br /><sub>Travis LaDuke</sub>](http://-)<br />[💡](#example-laduke "Examples") | [<img src="https://avatars2.githubusercontent.com/u/11290953?v=3" width="100px;"/><br /><sub>Aydın Çağrı Dumlu</sub>](https://github.com/acgrdumlu)<br />[🐛](https://github.com/paypal/glamorous/issues?q=author%3Aacgrdumlu "Bug reports") [💻](https://github.com/paypal/glamorous/commits?author=acgrdumlu "Code") | [<img src="https://avatars2.githubusercontent.com/u/1383861?v=3" width="100px;"/><br /><sub>Maja Wichrowska</sub>](https://github.com/majapw)<br />[🐛](https://github.com/paypal/glamorous/issues?q=author%3Amajapw "Bug reports") | [<img src="https://avatars3.githubusercontent.com/u/6845263?v=3" width="100px;"/><br /><sub>Tom Liu</sub>](https://github.com/gt3240)<br />[📖](https://github.com/paypal/glamorous/commits?author=gt3240 "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/1863771?v=3" width="100px;"/><br /><sub>Siddharth Kshetrapal</sub>](https://github.com/siddharthkp)<br />[⚠️](https://github.com/paypal/glamorous/commits?author=siddharthkp "Tests") [🔧](#tool-siddharthkp "Tools") |
| [<img src="https://avatars2.githubusercontent.com/u/5257243?v=3" width="100px;"/><br /><sub>WillowHQ</sub>](https://github.com/WillowHQ)<br />[📖](https://github.com/paypal/glamorous/commits?author=WillowHQ "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/12202757?v=4" width="100px;"/><br /><sub>Mohammad Rajabifard</sub>](https://tarino.ir)<br />[🐛](https://github.com/paypal/glamorous/issues?q=author%3Amorajabi "Bug reports") [📖](https://github.com/paypal/glamorous/commits?author=morajabi "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/17005317?v=3" width="100px;"/><br /><sub>Omar Albacha</sub>](https://github.com/Oalbacha)<br />[💻](https://github.com/paypal/glamorous/commits?author=Oalbacha "Code") [📖](https://github.com/paypal/glamorous/commits?author=Oalbacha "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/28659384?v=3" width="100px;"/><br /><sub>tdeschryver</sub>](https://github.com/tdeschryver)<br />[💻](https://github.com/paypal/glamorous/commits?author=tdeschryver "Code") [⚠️](https://github.com/paypal/glamorous/commits?author=tdeschryver "Tests") | [<img src="https://avatars0.githubusercontent.com/u/4955191?v=4" width="100px;"/><br /><sub>Dylan Mozlowski</sub>](https://github.com/DylanMoz)<br />[💻](https://github.com/paypal/glamorous/commits?author=DylanMoz "Code") | [<img src="https://avatars2.githubusercontent.com/u/3275424?v=4" width="100px;"/><br /><sub>andretshurotshka</sub>](https://github.com/goodmind)<br />[💻](https://github.com/paypal/glamorous/commits?author=goodmind "Code") [⚠️](https://github.com/paypal/glamorous/commits?author=goodmind "Tests") | [<img src="https://avatars3.githubusercontent.com/u/12836237?v=4" width="100px;"/><br /><sub>Danila</sub>](https://github.com/O4epegb)<br />[⚠️](https://github.com/paypal/glamorous/commits?author=O4epegb "Tests") |
| [<img src="https://avatars3.githubusercontent.com/u/12473268?v=4" width="100px;"/><br /><sub>Junyoung Clare Jang</sub>](http://ailrun.github.io/)<br />[💻](https://github.com/paypal/glamorous/commits?author=Ailrun "Code") [⚠️](https://github.com/paypal/glamorous/commits?author=Ailrun "Tests") |
| [<img src="https://avatars3.githubusercontent.com/u/12473268?v=4" width="100px;"/><br /><sub>Junyoung Clare Jang</sub>](http://ailrun.github.io/)<br />[💻](https://github.com/paypal/glamorous/commits?author=Ailrun "Code") [⚠️](https://github.com/paypal/glamorous/commits?author=Ailrun "Tests") | [<img src="https://avatars2.githubusercontent.com/u/897575?v=4" width="100px;"/><br /><sub>Björn Ricks</sub>](https://twitter.com/bjoernricks)<br />[🐛](https://github.com/paypal/glamorous/issues?q=author%3Abjoernricks "Bug reports") [💻](https://github.com/paypal/glamorous/commits?author=bjoernricks "Code") [📖](https://github.com/paypal/glamorous/commits?author=bjoernricks "Documentation") [⚠️](https://github.com/paypal/glamorous/commits?author=bjoernricks "Tests") |
<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors][all-contributors] specification.
Expand Down
101 changes: 101 additions & 0 deletions src/__tests__/index.filter-props.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/* eslint func-style:0, react/prop-types:0 */
import React from 'react'
import {mount as render} from 'enzyme'
import glamorous from '../'

test('filterProps are not passed to child component', () => {
const filterProps = ['bold']
const Child = props => <div {...props} />
const Text = glamorous(Child, {filterProps})(
{
fontSize: 20,
},
({bold}) => ({
fontWeight: bold ? 'bold' : undefined,
}),
)
const rendered = render(<Text bold id="1" />)
const child = rendered.find(Child)

expect(rendered.prop('bold')).toBe(true)
expect(rendered.prop('id')).toBe('1')
expect(child.prop('bold')).toBeUndefined()
expect(child.prop('id')).toBe('1')
})

test('filterProps takes precedence over built in props', () => {
const filterProps = ['id']
const Text = glamorous('div', {filterProps})()

const rendered = render(<Text bar="foo" id="1" lang="en" />)
const child = rendered.find('div')

expect(rendered.prop('bar')).toBe('foo')
expect(rendered.prop('id')).toBe('1')
expect(rendered.prop('lang')).toBe('en')
expect(child.prop('bar')).toBeUndefined()
expect(child.prop('id')).toBeUndefined()
expect(child.prop('lang')).toBe('en')
})

test('filterProps takes precedence over forwardProps', () => {
const filterProps = ['foo']
const forwardProps = ['foo', 'bar']
const Child = ({bar}) => <div id={bar} />
const Text = glamorous(Child, {
rootEl: 'div',
filterProps,
forwardProps,
})()

const rendered = render(<Text foo="bar" bar="foo" />)
const child = rendered.find(Child)

expect(rendered.prop('bar')).toBe('foo')
expect(rendered.prop('foo')).toBe('bar')
expect(child.prop('foo')).toBeUndefined()
expect(child.prop('bar')).toBe('foo')
expect(child.find('div').prop('id')).toBe('foo')
})

test('filterProps takes precedence over cssOverrides', () => {
const filterProps = ['foo']
const Text = glamorous('div', {
filterProps,
propsAreCssOverrides: true,
})(({foo}) => (foo ? {padding: '1'} : undefined))

const rendered = render(<Text margin={1} foo="bar" />)
const child = rendered.find('div')

expect(rendered.prop('margin')).toBe(1)
expect(rendered.prop('foo')).toBe('bar')
expect(child.prop('foo')).toBeUndefined()
expect(child.prop('margin')).toBeUndefined()
})

test('filterProps are applied to new component', () => {
const filterProps = ['shoulRender']
const Child = props => <div {...props} />
const Text = glamorous(Child, {filterProps})({
color: 'red',
fontSize: 20,
})
const View = Text.withComponent('div')

expect(View.filterProps).toEqual(filterProps)
})

test('filterProps can be overridden for the new component', () => {
const Child = props => <div {...props} />
const Text = glamorous(Child, {filterProps: ['shouldRender']})({
color: 'red',
fontSize: 20,
})
const filterProps = ['other-thing']
const View = Text.withComponent('div', {filterProps})

expect(View.filterProps).toEqual(filterProps)
})

// vim: set ts=2 sw=2 tw=80:
18 changes: 14 additions & 4 deletions src/create-glamorous.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function createGlamorous(splitProps) {
rootEl,
displayName,
shouldClassNameUpdate,
filterProps = [],
forwardProps = [],
propsAreCssOverrides = comp.propsAreCssOverrides,
withProps: basePropsToApply,
Expand Down Expand Up @@ -101,15 +102,20 @@ function createGlamorous(splitProps) {
}

function withComponent(newComp, options = {}) {
const {forwardProps: fp, ...componentProperties} = GlamorousComponent
const {
forwardProps: fwp,
filterProps: flp,
...componentProperties
} = GlamorousComponent
return glamorous(
{
...componentProperties,
comp: newComp,
},
{
// allows the forwardProps to be overridden
forwardProps: fp,
// allows the forwardProps and filterProps to be overridden
forwardProps: fwp,
filterProps: flp,
...options,
},
)()
Expand Down Expand Up @@ -149,6 +155,7 @@ function createGlamorous(splitProps) {
comp,
styles,
rootEl,
filterProps,
forwardProps,
displayName,
propsToApply: basePropsToApply,
Expand All @@ -169,6 +176,7 @@ function createGlamorous(splitProps) {
comp,
styles,
rootEl,
filterProps,
forwardProps,
displayName,
propsToApply: basePropsToApply,
Expand All @@ -186,8 +194,10 @@ function createGlamorous(splitProps) {
// component in glamorous
comp: componentsComp,
rootEl: rootEl || componentsComp,
// join forwardProps (for anyone doing: glamorous(glamorous.a({}), {}))
// join forwardProps and filterProps
// (for anyone doing: glamorous(glamorous.a({}), {}))
forwardProps: when(comp.forwardProps, forwardProps),
filterProps: when(comp.filterProps, filterProps),
// set the displayName to something that's slightly more
// helpful than `GlamorousComponent` :)
displayName: displayName || `glamorous(${getDisplayName(comp)})`,
Expand Down
12 changes: 7 additions & 5 deletions src/split-props.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,21 @@ export default function splitProps(
// component ever
...rest
},
{propsAreCssOverrides, rootEl, forwardProps},
{propsAreCssOverrides, rootEl, filterProps, forwardProps},
) {
const returnValue = {toForward: {}, cssProp, cssOverrides: {}}
if (!propsAreCssOverrides) {
if (typeof rootEl !== 'string') {
// if it's not a string, then we can forward everything
// (because it's a component)
if (typeof rootEl !== 'string' && filterProps.length === 0) {
// if it's not a string and filterProps is empty,
// then we can forward everything (because it's a component)
returnValue.toForward = rest
return returnValue
}
}
return Object.keys(rest).reduce((split, propName) => {
if (
if (filterProps.indexOf(propName) !== -1) {
return split
} else if (
forwardProps.indexOf(propName) !== -1 ||
shouldForwardProperty(rootEl, propName)
) {
Expand Down

0 comments on commit a94d620

Please sign in to comment.