Repository: UniversalAvenue/react-compose Branch: master Commit: 3fd02c2dc633 Files: 20 Total size: 62.5 KB Directory structure: gitextract_1fv0fe_m/ ├── .babelrc ├── .eslintrc.js ├── .gitignore ├── LICENSE ├── README.md ├── circle.yml ├── lib/ │ ├── __tests__/ │ │ ├── compose-test.js │ │ └── connect-test.js │ ├── config.js │ ├── connect.js │ ├── getDisplayName.js │ └── index.js ├── package.json └── src/ ├── __tests__/ │ ├── .eslintrc.js │ ├── compose-test.js │ └── connect-test.js ├── config.js ├── connect.js ├── getDisplayName.js └── index.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .babelrc ================================================ { "presets": [ "react", "stage-0", "es2015" ], "plugins": [ "lodash" ], } ================================================ FILE: .eslintrc.js ================================================ module.exports = { extends: 'airbnb', parser: 'babel-eslint', plugins: [ 'react', ], rules: { 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'], }], }, }; ================================================ FILE: .gitignore ================================================ # Logs logs *.log # Runtime data pids *.pid *.seed # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # node-waf configuration .lock-wscript # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directory # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git node_modules *.sw* ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 UniversalAvenue Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ ![React Compose](https://s3.amazonaws.com/f.cl.ly/items/1y000n0q2a2n0L2Y243S/react-compose-logo@2x.png) [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) [![Circle CI](https://circleci.com/gh/UniversalAvenue/react-compose/tree/master.svg?style=svg)](https://circleci.com/gh/UniversalAvenue/react-compose/tree/master) **React-compose** allows you to encapsulate component logic into smaller, reusable functions, which in turn can be combined back into component. The fundamental idea is that React components has a way of becoming bloated with, often repeated, logic. This lib provides you with a set of tools to avoid that. The encapsulated pieces will be easily testable, either because they are constant or since their functionality has a more narrow scope than a corresponding component would have. The other aspect of **react-compose** is based upon the fact that whenever you create a React component, you also create an api for it as well. It is essential, for any large scale project that this api is well formed and consistent across the application. Most components should also be extendable too, which is why, significant care is needed to make sure that each component doesn't break these rules. Let's show a simple example of extendablity: ```javascript const ButtonComponent = props => { const { onClick, label, } = props; return ; }; ``` Now if a developer would like to manipulate the style of `ButtonComponent` from the outside, it would have to be changed accordingly: ```javascript const ButtonComponent = props => { const { onClick, style, label, } = props; return ; }; ``` On the other hand, if all props should be passed down to the `button` element, the following is much more useful: ```javascript const ButtonComponent = props => { const { label, } = props; return ; }; ``` With **react-compose**, the above would be written as: ```javascript const labelToChildren = ({ label }) => ({ children: label }); const ButtonComponent = compose(labelToChildren)('button'); ``` Leaving much less room for breaking the rules of extendability and resuability. The CustomComponent should essentially work as you would expect that the basic html elements does, `ButtonComponent` ~ `button`, beyond of course the added behavior. As an extra bonus, it is also more straight forward to test the encapsulated behavior rather than the component as a whole. ```javascript describe('labelToChildren', () => { it('should pass whatever input label as children', () => { expect(labelToChildren({ label: 'string' }).children).toEqual('string'); }); }); ``` Finally, the heart of **react-compose**, is finding those elementary patterns that are present in your application. In this case, we can create a nice higher order function for the `labelToChildren` logic. ```javascript const mixProp = (from, to) => props => ({ [to]: props[from] }); const labelToChildren = mixProp('label', 'children'); ``` ## Installation Install package, and check that you are using a matching version of React (^0.14) ```bash npm install -s react-compose ``` ## API Example api usage: ```javascript import { compose } from 'react-compose'; const constantProper = { age: 15, }; const dynamicProper = props => { return { children: `The cat is ${props.age} years old`, }; }; const Cat = compose(constantProper, dynamicProper)('p'); // =>

The cat is 15 years old

; ``` Specialized style composing ```javascript import { compose, styles } from 'react-compose'; const constantStyle = { background: 'red', }; const dynamicStyle = ({ isActive }) => (!isActive && { display: 'none', }); const Component = compose(styles(constantStyle, dynamicStyle))('p'); return (props) => { return Some text; }; ``` Stacking custom components ```javascript import { compose } from 'react-compose'; const Cat = props => { return

The cat is {props.age} years old

; }; const injectAge = { age: 5, }; const Composed = compose(injectAge)(Cat); // =>

The cat is 5 years old

``` Composing complex children values ```javascript import { compose, children } from 'react-compose'; const AgeInfo = props => { return

Age: {props.age} years

; }; const LengthInfo = props => { return

Length: {props.length} cm

; }; const HeightInfo = props => { return

Height: {props.height} cm

; }; const Info = compose(children(AgeInfo, LengthInfo, HeightInfo))('div'); const dogData = { age: 5, length: 250, height: 150, }; const DogInfo = compose(dogData)(Info); // =>
//

Age: 5

//

Length: 250

//

Height: 150

//
``` Composing classNames, using the awesome [classnames](https://github.com/JedWatson/classnames) lib ```javascript import { compose, classNames } from 'react-compose'; const btnClassNames = classNames('btn', ({ pressed }) => pressed && 'btn-pressed', ({ hover }) => hover && 'btn-hover'); const Button = compose(btnClassNames)('button'); // pressed: true =>