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

Commit

Permalink
feat: add flattenProps hoc
Browse files Browse the repository at this point in the history
Closes #77
  • Loading branch information
gregberge committed May 11, 2017
1 parent f3c6aa8 commit 11e6e25
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 5 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
"hoist-non-react-statics": "^1.2.0",
"object.omit": "^2.0.1",
"object.pick": "^1.2.0",
"symbol-observable": "^1.0.4"
"symbol-observable": "^1.0.4",
"warning": "^3.0.0"
},
"devDependencies": {
"babel-cli": "^6.24.1",
Expand Down
5 changes: 5 additions & 0 deletions src/__tests__/flattenProp.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import React from 'react'
import warning from 'warning'
import { shallow } from 'enzyme'
import { Dummy } from './utils'
import { compose, flattenProp, pure } from '../'

jest.mock('warning')

describe('flattenProp', () => {
it('should flatten an object prop and spreads it into the top-level props object', () => {
const Counter = flattenProp('state')(Dummy)

expect(warning).toHaveBeenCalledWith(true, '`flattenProp` is deprecated, please use `flattenProps` instead.')

const wrapper = shallow(
<Counter pass="through" state={{ counter: 1 }} />,
)
Expand Down
60 changes: 60 additions & 0 deletions src/__tests__/flattenProps.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from 'react'
import { shallow } from 'enzyme'
import { Dummy } from './utils'
import { compose, flattenProps, pure } from '../'

describe('flattenProps', () => {
it('should flatten an object prop and spread it into the top-level props object', () => {
const Counter = flattenProps('a')(Dummy)

const wrapper = shallow(
<Counter pass="through" a={{ z: 1 }} />,
)

expect(wrapper.equals(
<Dummy pass="through" a={{ z: 1 }} z={1} />,
)).toBe(true)

wrapper.setProps({
pass: 'through',
a: { a: 1 },
})

expect(wrapper.equals(
<Dummy pass="through" a={1} />,
)).toBe(true)
})

it('should flatten several props', () => {
const Counter = flattenProps(['a', 'b'])(Dummy)

const wrapper = shallow(
<Counter pass="through" a={{ z: 1 }} b={{ y: 2 }} />,
)

expect(wrapper.equals(
<Dummy pass="through" a={{ z: 1 }} b={{ y: 2 }} z={1} y={2} />,
)).toBe(true)

wrapper.setProps({
pass: 'through',
a: { a: 1 },
b: { b: 1 },
})

expect(wrapper.equals(
<Dummy pass="through" a={1} b={1} />,
)).toBe(true)
})

it('should be merged with other hoc', () => {
const Component = compose(
flattenProps('foo'),
pure,
)(Dummy)

const wrapper = shallow(<Component />)
expect(wrapper.instance().constructor.displayName).toBe('flattenProps(pure(Dummy))')
expect(wrapper.equals(<Dummy />)).toBe(true)
})
})
16 changes: 12 additions & 4 deletions src/flattenProp.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import warning from 'warning'
import createHelper from './createHelper'
import mapProps from './mapProps'

Expand All @@ -6,16 +7,23 @@ import mapProps from './mapProps'
*
* @static
* @category Higher-order-components
* @deprecated since v3.0.0, use flattenProps instead
* @param {String} propName Name of the prop to flatten.
* @returns {HigherOrderComponent} A function that takes a component and returns a new component.
* @example
*
* const Button = flattenProp('props')('button');
* <Button props={{type: 'submit'}} /> // will render <button type="submit" />
*/
const flattenProp = propName => mapProps(props => ({
...props,
...props[propName],
}))
const flattenProp = (propName) => {
if (process.env.NODE_ENV !== 'production') {
warning(true, '`flattenProp` is deprecated, please use `flattenProps` instead.')
}

return mapProps(props => ({
...props,
...props[propName],
}))
}

export default createHelper(flattenProp, 'flattenProp')
26 changes: 26 additions & 0 deletions src/flattenProps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import createHelper from './createHelper'
import mapProps from './mapProps'

/**
* Flattens one or several props so that its fields are spread out into the props object.
*
* @static
* @category Higher-order-components
* @alias flattenProp
* @param {String|String[]} paths The property paths to flatten.
* @returns {HigherOrderComponent} A function that takes a component and returns a new component.
* @example
*
* const Button = flattenProps(['a', 'b'])('button');
* // Will render <button type="submit" className="btn" />
* <Button a={{type: 'submit'}} b={{className: 'btn'}} />
*/
const flattenProps = paths => mapProps((props) => {
if (typeof paths === 'string') {
return { ...props, ...props[paths] }
}

return paths.reduce((nextProps, path) => ({ ...nextProps, ...props[path] }), props)
})

export default createHelper(flattenProps, 'flattenProps')
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export { default as createSink } from './createSink'
export { default as debug } from './debug'
export { default as defaultProps } from './defaultProps'
export { default as flattenProp } from './flattenProp'
export { default as flattenProps } from './flattenProps'
export { default as getContext } from './getContext'
export { default as getDisplayName } from './getDisplayName'
export { default as hoistStatics } from './hoistStatics'
Expand Down
6 changes: 6 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5688,6 +5688,12 @@ walker@~1.0.5:
dependencies:
makeerror "1.0.x"

warning@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c"
dependencies:
loose-envify "^1.0.0"

watch@~0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc"
Expand Down

0 comments on commit 11e6e25

Please sign in to comment.