├── .babelrc ├── .eslintrc.json ├── .gitignore ├── .npmignore ├── CONTRIBUTING.md ├── README.md ├── bs-config.json ├── examples └── test-app │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── public │ ├── favicon.ico │ └── index.html │ ├── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── index.css │ ├── index.js │ └── logo.svg │ └── yarn.lock ├── package.json ├── rollup.config.js ├── src ├── __snapshots__ │ └── createStyleHoc.test.js.snap ├── createStyleHoc.js ├── createStyleHoc.test.js ├── helpers │ ├── generateStyleObject.test.js │ └── index.js ├── index.js ├── withMargin.js └── withPadding.js ├── yarn-error.log └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react", "es2015"], 3 | "plugins": ["transform-object-rest-spread"], 4 | "env": { 5 | "test": { 6 | "plugins": ["istanbul", "transform-object-rest-spread", "rewire"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaVersion": 6, 3 | "env": { 4 | "es6": true, 5 | "mocha": true, 6 | "node": true, 7 | "jest": true 8 | }, 9 | "parserOptions": { 10 | "ecmaVersion": 6, 11 | "sourceType": "module", 12 | "ecmaFeatures": { 13 | "jsx": true, 14 | "experimentalObjectRestSpread": true 15 | } 16 | }, 17 | "plugins": [ 18 | "react" 19 | ], 20 | "rules": { 21 | "react/jsx-uses-react": "error", 22 | "react/jsx-uses-vars": "error", 23 | "brace-style": 1, 24 | "camelcase": [1, { 25 | "properties": "never" 26 | }], 27 | "comma-spacing": [1, { 28 | "before": false, 29 | "after": true 30 | }], 31 | "comma-style": [1, "last"], 32 | "eol-last": 1, 33 | "eqeqeq": [1, "allow-null"], 34 | "func-call-spacing": [1, "never"], 35 | "indent": [1, 2, { 36 | "SwitchCase": 1 37 | }], 38 | "key-spacing": [1, { 39 | "beforeColon": false, 40 | "afterColon": true 41 | }], 42 | "keyword-spacing": [1, { 43 | "before": true, 44 | "after": true 45 | }], 46 | "new-parens": 1, 47 | "no-case-declarations": 1, 48 | "no-cond-assign": 1, 49 | "no-console": 1, 50 | "no-constant-condition": 1, 51 | "no-debugger": 1, 52 | "no-dupe-args": 1, 53 | "no-dupe-keys": 1, 54 | "no-duplicate-case": 1, 55 | "no-empty": 1, 56 | "no-empty-character-class": 1, 57 | "no-ex-assign": 1, 58 | "no-extra-semi": 1, 59 | "no-func-assign": 1, 60 | "no-invalid-regexp": 1, 61 | "no-irregular-whitespace": 1, 62 | "no-mixed-spaces-and-tabs": 1, 63 | "no-new-object": 1, 64 | "no-obj-calls": 1, 65 | "no-plusplus": 1, 66 | "no-redeclare": 1, 67 | "no-regex-spaces": 1, 68 | "no-sparse-arrays": 1, 69 | "no-tabs": 1, 70 | "no-trailing-spaces": 1, 71 | "no-undef": 1, 72 | "no-unexpected-multiline": 1, 73 | "no-unreachable": 1, 74 | "no-unsafe-finally": 1, 75 | "no-unused-vars": [1, { 76 | "vars": "all", 77 | "args": "none" 78 | }], 79 | "no-whitespace-before-property": 1, 80 | "semi": [1, "always"], 81 | "semi-spacing": [1, { 82 | "before": false, 83 | "after": true 84 | }], 85 | "space-before-blocks": [1, "always"], 86 | "space-before-function-paren": [0, { 87 | "anonymous": "always", 88 | "named": "never" 89 | }], 90 | "space-in-parens": [1, "never"], 91 | "space-infix-ops": 1, 92 | "space-unary-ops": [1, { 93 | "words": true, 94 | "nonwords": false 95 | }], 96 | "strict": [1, "safe"], 97 | "unicode-bom": [1, "never"], 98 | "use-isnan": 1, 99 | "valid-typeof": 1 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | dist 3 | node_modules 4 | coverage 5 | .nyc_output 6 | npm-debug.log -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | .* 3 | coverage 4 | test 5 | rollup.config.js 6 | bs-config.json 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Thanks for wanting to contribute to react-style-hoc! 2 | 3 | Below you can find a list of things we need to decide on, to move forward with this library. 4 | 5 | Should you decide to open a PR, please make sure to run all tests (`npm test`) first, and include any relevant tests for your feature. 6 | 7 | 8 | # to do: 9 | - add more utility functions 10 | - how shall we handle auto prefixing? 11 | - can we extract a CSS file from the final inline style that was generated? Similar to a JSS approach? 12 | - what about performance? -> we need some benchmarking 13 | - How do we want to expose things like align-items for flexbox? 14 | - Do we want to provide default positioning utilities? 15 | - Should everything be a function, or do we allow more configuration as params..? 16 | - .... -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Installation: 2 | 3 | `yarn add react-style-hoc` 4 | 5 | or if you prefer `npm`: 6 | 7 | `npm install --save react-style-hoc` 8 | 9 | 10 | # [motivation] Why would I want to compose styles with functions...?! 11 | 12 | Great question! 13 | 14 | The purpose of this repository is to allow you to declare styles as functions, that are composable, and return a react Higher Order Component. 15 | 16 | The direct benefit of which is that it becomes possible to create reusable HOCs for styling. 17 | 18 | This is probably not very useful for 'looks-and-feel' styles (everything 'inside the component box') - but more for things that have to do with positioning. Separating those two concerns is a good idea in any case, and this provides you with a tool to do so. 19 | 20 | 21 | A simple example would be to define a flex centerer, which would look something like this: 22 | 23 | ``` 24 | const MyComponent = ({style}) =>
unstyled
25 | 26 | const isFlexBox = createStyleHoc('display', 'flex'); 27 | const centersChidren = createStyleHoc({alignItems: 'center', justifyContent: 'center'}, ''); 28 | 29 | const isFlexCenterer = compose( 30 | isFlexBox, 31 | centersChildren 32 | ) 33 | ``` 34 | 35 | When using `isFlexCenterer` on it's own as a wrapper around `MyComponent`, like this:... 36 | 37 | ``` 38 | export isFlexCenterer(MyComponent); 39 | ``` 40 | 41 | the `style` prop of `MyComponent` then looks like this: 42 | 43 | ``` 44 | { 45 | display: 'flex', 46 | alignItems: 'center', 47 | justifyContent: 'center', 48 | } 49 | 50 | ``` 51 | 52 | Of course, the power of composing styles only becomes fully clear once you start composing different helpers. 53 | 54 | You can compare this to using `mixins` in a CSS preprocessor such as SASS or LESS. 55 | 56 | ``` 57 | const isFullyStyled = compose( 58 | withMargin(20), 59 | withPadding(40), 60 | isFlexCenterer, 61 | withColor, 62 | .... 63 | ) 64 | ``` 65 | 66 | 67 | This is a very young library, and contributions very welcome! 68 | 69 | # Development: 70 | 71 | `yarn install` 72 | 73 | `npm run watch:js` 74 | 75 | run tests: `npm test` 76 | 77 | # Example: 78 | run [our example app](https://github.com/ambewas/react-style-hoc/tree/master/examples/test-app) 79 | 80 | # How to use: 81 | 82 | ``` 83 | import React, { Component } from 'react'; 84 | import { withPadding, withMargin, compose, createStyleHoc } from 'react-style-hoc'; 85 | ``` 86 | 87 | ## Compose styles with our default provided style HOCs 88 | ``` 89 | const withPaddingAndMargin = compose( 90 | withPadding(20), 91 | withMargin(50), 92 | ); 93 | 94 | ``` 95 | 96 | ## ... or create your own style HOCS using `createStyleHoc`: 97 | Pass a string (style key). Everything here is curried, so if no default value is provided, you still have to call `withColor` with a value -> see usage in `withAllStyles` 98 | ``` 99 | const withColor = createStyleHoc('color'); 100 | ``` 101 | 102 | ## Pass style key & value as arguments: 103 | ``` 104 | const withSomeRandomStyleAsArguments = createStyleHoc('display', 'flex'); 105 | ``` 106 | 107 | ## Pass an object with default styles applied: 108 | 109 | Note: we need that second argument. We still need figure out how to get rid of that. Should we even expose this kind of API? Thoughts are welcome. 110 | ``` 111 | const withSomeRandomStyleAsObject = createStyleHoc({ 112 | background: 'purple', 113 | }, ''); 114 | ``` 115 | 116 | ## Compose all previously made styles into one! 117 | ``` 118 | const withAllStyles = compose( 119 | withSomeRandomStyleAsArguments, 120 | withSomeRandomStyleAsObject, 121 | withPaddingAndMargin, 122 | withColor('#78a5ff'), 123 | ) 124 | ``` 125 | 126 | 127 | ## Use the hoc on your stateless components: 128 | 129 | Note: you can still provide some other default style as a prop, the HOC styles will be applied after -- so its possible to override everything. E.g. if we would have provided `{padding: '1px'}`, then `withPadding(20)` from before would not have any effect. 130 | ``` 131 | const TestStateless = ({ children, style }) =>
{children}
132 | const Styled = withAllStyles(TestStateless); 133 | 134 | class App extends Component { 135 | render() { 136 | return ( 137 |
138 | hello 139 | 140 |
with padding, composed with margin
141 |
test
142 |
test
143 |
test
144 |
test
145 |
146 |
147 | ); 148 | } 149 | } 150 | 151 | export default App; 152 | 153 | ``` 154 | 155 | # Contributing 156 | 157 | Please see our guidelines in `CONTRIBUTING.md` if you want to contribute something to this library. 158 | 159 | # License 160 | 161 | MIT Licensed. Copyright (c) Kevin Decock 2017. -------------------------------------------------------------------------------- /bs-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 3060, 3 | "server": { 4 | "baseDir": "./coverage/lcov-report" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /examples/test-app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | npm-debug.log* 16 | yarn-debug.log* 17 | yarn-error.log* 18 | 19 | -------------------------------------------------------------------------------- /examples/test-app/README.md: -------------------------------------------------------------------------------- 1 | This is an example app to check out react-style-hoc. 2 | 3 | to run it locally: 4 | 5 | `yarn install` 6 | 7 | `yarn start` -------------------------------------------------------------------------------- /examples/test-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm-test-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^15.5.4", 7 | "react-dom": "^15.5.4", 8 | "react-style-hoc": "^0.3.0" 9 | }, 10 | "devDependencies": { 11 | "react-scripts": "0.9.5" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test --env=jsdom", 17 | "eject": "react-scripts eject" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/test-app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ambewas/react-style-hoc/f0df09b72d903a0f19cbde8338dcadbf08fb0774/examples/test-app/public/favicon.ico -------------------------------------------------------------------------------- /examples/test-app/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 16 | React App 17 | 18 | 19 |
20 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /examples/test-app/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-intro { 18 | font-size: large; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { transform: rotate(0deg); } 23 | to { transform: rotate(360deg); } 24 | } 25 | -------------------------------------------------------------------------------- /examples/test-app/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { withPadding, withMargin, compose, createStyleHoc } from 'react-style-hoc'; 3 | 4 | // compose styles with our default provided style HOCs 5 | const withPaddingAndMargin = compose( 6 | withPadding(20), 7 | withMargin(50) 8 | ); 9 | 10 | 11 | // ... or create your own style HOCS using createStyleHoc: 12 | // pass a string (style key) -> see usage in `withAllStyles` 13 | const withColor = createStyleHoc('color'); 14 | 15 | // pass an object with default styles applied: 16 | // need that second argument. Gotta figure out how to get rid of it -- but it's curried, so...? 17 | const withSomeRandomStyleAsObject = createStyleHoc({ 18 | background: 'purple', 19 | }, ''); 20 | 21 | // pass style key & value as arguments: 22 | const withSomeRandomStyleAsArguments = createStyleHoc('display', 'flex'); 23 | 24 | // compose all previously made styles into one! 25 | const withAllStyles = compose( 26 | withSomeRandomStyleAsArguments, 27 | withSomeRandomStyleAsObject, 28 | withPaddingAndMargin, 29 | withColor('#78a5ff') 30 | ); 31 | 32 | const TestStateless = ({ children, style }) =>
{children}
; 33 | const Styled = withAllStyles(TestStateless); 34 | 35 | class App extends Component { 36 | render() { 37 | return ( 38 |
39 | hello 40 | 41 |
with padding, composed with margin
42 |
test
43 |
test
44 |
test
45 |
test
46 |
47 |
48 | ); 49 | } 50 | } 51 | 52 | export default App; 53 | -------------------------------------------------------------------------------- /examples/test-app/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /examples/test-app/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /examples/test-app/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | import './index.css'; 5 | 6 | ReactDOM.render( 7 | , 8 | document.getElementById('root') 9 | ); 10 | -------------------------------------------------------------------------------- /examples/test-app/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-style-hoc", 3 | "version": "0.3.4", 4 | "description": "React higher order component - adds style related props to wrapped components", 5 | "main": "dist/index.js", 6 | "keywords": [ 7 | "react", 8 | "hoc", 9 | "style", 10 | "stylus", 11 | "compass", 12 | "style mixins functions", 13 | "style composition", 14 | "composing styles", 15 | "composing css", 16 | "composing", 17 | "createStyleHoc", 18 | "higher order component", 19 | "props" 20 | ], 21 | "author": "kevin decock", 22 | "license": "ISC", 23 | "scripts": { 24 | "watch:js": "onchange \"src/\" -- npm run bundle", 25 | "clear": "rimraf dist/**", 26 | "lint": "esw src", 27 | "lint:watch": "esw src -w", 28 | "test": "jest --env=jsdom --watch", 29 | "test:watch": "npm run test -- -w", 30 | "test:coverage": "nyc --reporter=lcov --reporter=text-summary npm test", 31 | "coverage:serve": "lite-server", 32 | "rollup": "rollup --config rollup.config.js", 33 | "build": "npm run rollup", 34 | "bundle": "npm-run-all -s lint build", 35 | "prepublish": "npm-run-all -s clear bundle" 36 | }, 37 | "devDependencies": { 38 | "babel-cli": "^6.24.1", 39 | "babel-plugin-external-helpers": "^6.22.0", 40 | "babel-plugin-istanbul": "^4.1.3", 41 | "babel-plugin-rewire": "^1.1.0", 42 | "babel-plugin-transform-object-rest-spread": "^6.23.0", 43 | "babel-polyfill": "^6.23.0", 44 | "babel-preset-es2015": "^6.24.1", 45 | "babel-preset-es2015-rollup": "^3.0.0", 46 | "babel-preset-react": "^6.24.1", 47 | "copy": "^0.3.0", 48 | "cross-env": "^5.0.0", 49 | "eslint": "^3.19.0", 50 | "eslint-plugin-react": "^7.0.1", 51 | "eslint-watch": "^3.1.0", 52 | "istanbul": "^0.4.5", 53 | "jest": "^20.0.3", 54 | "lite-server": "^2.3.0", 55 | "npm-run-all": "^4.0.2", 56 | "npm-watch": "^0.1.9", 57 | "nyc": "^10.3.2", 58 | "onchange": "^3.2.1", 59 | "react-test-renderer": "^15.5.4", 60 | "rimraf": "^2.6.1", 61 | "rollup": "^0.41.6", 62 | "rollup-plugin-babel": "^2.7.1", 63 | "rollup-plugin-jsx": "^1.0.3", 64 | "rollup-plugin-uglify-es": "^0.0.1", 65 | "uglify-es": "^3.0.8" 66 | }, 67 | "nyc": { 68 | "include": [ 69 | "src/*.js" 70 | ], 71 | "require": [ 72 | "mocha", 73 | "babel-register", 74 | "babel-polyfill" 75 | ], 76 | "sourceMap": false, 77 | "instrument": false 78 | }, 79 | "repository": { 80 | "type": "git", 81 | "url": "https://github.com/ambewas/react-style-hoc" 82 | }, 83 | "engines": { 84 | "node": ">= 4.2.1", 85 | "npm": ">= 3" 86 | }, 87 | "dependencies": { 88 | "ramda": "^0.23.0", 89 | "react": "^15.5.4" 90 | }, 91 | "peerDependencies": { 92 | "react": "^15.5.4" 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | const babel = require('rollup-plugin-babel'); 2 | const uglify = require('rollup-plugin-uglify-es'); 3 | const minify = require('uglify-es').minify; 4 | const jsx = require('rollup-plugin-jsx'); 5 | 6 | export default { 7 | entry: 'src/index.js', 8 | format: 'umd', 9 | external: [ 10 | // add external packages here 11 | // e.g. 'rxjs/Observable' 12 | 'ramda', 13 | 'react' 14 | ], 15 | dest: 'dist/index.js', 16 | sourceMap: true, 17 | moduleId: 'react-style-hoc', 18 | moduleName: 'Style', 19 | globals: { 20 | // add external packages as globals here 21 | // e.g. 'rxjs/Observable': 'rxjs_Observable' 22 | 'ramda': 'ramda', 23 | 'react': 'react' 24 | }, 25 | plugins: [ 26 | jsx({ factory: 'React.createElement' }), 27 | babel({ 28 | babelrc: false, 29 | presets: ['es2015-rollup'], 30 | plugins: ['transform-object-rest-spread', 'external-helpers'], 31 | exclude: 'node_modules/**' 32 | }), 33 | uglify({}, minify) 34 | ] 35 | }; 36 | -------------------------------------------------------------------------------- /src/__snapshots__/createStyleHoc.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`createStyleHoc when using createStyleHoc with a style object, it should add the correct style prop 1`] = ` 4 |
12 | unstyled 13 |
14 | `; 15 | 16 | exports[`createStyleHoc when wrapping a component in a HOC created by createStyleHoc, it should add the correct style prop 1`] = ` 17 |
24 | unstyled 25 |
26 | `; 27 | -------------------------------------------------------------------------------- /src/createStyleHoc.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; // eslint-disable-line 2 | 3 | import { curry } from 'ramda'; 4 | import { generateStyleObject } from './helpers/index.js'; 5 | 6 | export const createStyleHoc = curry((style, value, WrappedComponentOrStyle) => { 7 | // style -> e.g. { margin: 10, padding: 30 } || ['margin', 'padding'] || 'margin' 8 | // we should support default styles, an array of style values to be added, or one string. 9 | 10 | let newStyleObject = generateStyleObject(style, value); 11 | 12 | /** 13 | |-------------------------------------------------- 14 | | how can we detect is a component has been passed through, 15 | | and otherwise simply generate a style object? -- useful for 16 | | composing without having to depend on react. 17 | |-------------------------------------------------- 18 | */ 19 | 20 | return ({ style, ...props }) => { 21 | return ; 22 | }; 23 | }); 24 | -------------------------------------------------------------------------------- /src/createStyleHoc.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; // eslint-disable-line 2 | import renderer from 'react-test-renderer'; 3 | import { createStyleHoc } from './createStyleHoc.js'; 4 | 5 | const TestComponent = ({ style }) =>
unstyled
; 6 | 7 | describe('createStyleHoc', () => { 8 | 9 | 10 | it('should return a HOC', () => { 11 | expect(createStyleHoc()).toBeInstanceOf(Function); 12 | expect(createStyleHoc('margin')).toBeInstanceOf(Function); 13 | expect(createStyleHoc({margin: 10})).toBeInstanceOf(Function); 14 | expect(createStyleHoc({margin: 10}, '')).toBeInstanceOf(Function); 15 | }); 16 | 17 | test('when wrapping a component in a HOC created by createStyleHoc, it should add the correct style prop', function() { 18 | const withMargin = createStyleHoc('padding', 10); 19 | const Styled = withMargin(TestComponent); // eslint-disable-line 20 | 21 | const component = renderer.create( 22 | qdsf 23 | ); 24 | 25 | const tree = component.toJSON(); 26 | expect(tree).toMatchSnapshot(); 27 | expect(tree.props.style).toEqual({ padding: 10 }); 28 | }); 29 | 30 | test('when using createStyleHoc with a style object, it should add the correct style prop', function() { 31 | const withMargin = createStyleHoc({padding: 10, margin: 40}, ''); 32 | const Styled = withMargin(TestComponent); // eslint-disable-line 33 | 34 | const component = renderer.create( 35 | qdsf 36 | ); 37 | 38 | const tree = component.toJSON(); 39 | expect(tree).toMatchSnapshot(); 40 | expect(tree.props.style).toEqual({ padding: 10, margin: 40 }); 41 | }); 42 | }); 43 | 44 | -------------------------------------------------------------------------------- /src/helpers/generateStyleObject.test.js: -------------------------------------------------------------------------------- 1 | import { generateStyleObject } from './index.js'; 2 | 3 | describe('generateStyleObject', () => { 4 | it('should return undefined if no arguments are passed', () => { 5 | const style = generateStyleObject(); 6 | expect(style).toBeUndefined(); 7 | }); 8 | 9 | it('should return the passed style object if an object was passed', () => { 10 | const styleObject = { margin: '1' }; 11 | const style = generateStyleObject(styleObject); 12 | expect(style).toEqual(styleObject); 13 | }); 14 | 15 | it('should generate a style object when an array with style keys has been passed', () => { 16 | const styleArray = ['margin', 'padding']; 17 | const style = generateStyleObject(styleArray); 18 | const expectedStyle = { 19 | margin: undefined, 20 | padding: undefined 21 | }; 22 | expect(style).toEqual(expectedStyle); 23 | }); 24 | 25 | it('should generate a style object when a single string has been passed', () => { 26 | const styleArray = 'margin'; 27 | const style = generateStyleObject(styleArray); 28 | const expectedStyle = { 29 | margin: undefined, 30 | }; 31 | expect(style).toEqual(expectedStyle); 32 | }); 33 | }); 34 | 35 | -------------------------------------------------------------------------------- /src/helpers/index.js: -------------------------------------------------------------------------------- 1 | export const generateStyleObject = (style, value) => { 2 | if (!style) { 3 | return undefined; 4 | } 5 | 6 | // it's a style object with defaults 7 | if (typeof style === 'object' && !Array.isArray(style)) { 8 | return style; 9 | } 10 | 11 | // just an array with style keys 12 | if (Array.isArray(style)) { 13 | return Object.assign(...style.map(key => ({ [key]: value }))); 14 | } 15 | 16 | // a style key string 17 | return Object.assign({ [style]: value }); 18 | }; -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export { withPadding } from './withPadding'; 2 | export { withMargin } from './withMargin'; 3 | export { createStyleHoc } from './createStyleHoc.js'; 4 | export { compose } from 'ramda'; 5 | -------------------------------------------------------------------------------- /src/withMargin.js: -------------------------------------------------------------------------------- 1 | import { createStyleHoc } from './createStyleHoc.js'; 2 | export const withMargin = createStyleHoc('margin'); 3 | -------------------------------------------------------------------------------- /src/withPadding.js: -------------------------------------------------------------------------------- 1 | import { createStyleHoc } from './createStyleHoc.js'; 2 | export const withPadding = createStyleHoc('padding'); 3 | -------------------------------------------------------------------------------- /yarn-error.log: -------------------------------------------------------------------------------- 1 | Arguments: 2 | /Users/kevindecock1/.nvm/versions/node/v6.3.0/bin/node /Users/kevindecock1/.nvm/versions/node/v6.3.0/bin/yarn install 3 | 4 | PATH: 5 | /Users/kevindecock1/.nvm/versions/node/v6.3.0/bin:/usr/local/sbin:/Users/kevindecock1/.rvm/gems/ruby-2.2.0/bin:/Users/kevindecock1/.rvm/gems/ruby-2.2.0@global/bin:/Users/kevindecock1/.rvm/rubies/ruby-2.2.0/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:ANDROID_HOME/tools:ANDROID_HOME/platform-tools:/opt/X11/bin:/usr/local/opt/go/libexec/bin:/Users/kevindecock1/.rvm/bin:/urs/local/Cellar/elixir:/usr/local/bin/psql 6 | 7 | Yarn version: 8 | 0.24.4 9 | 10 | Node version: 11 | 6.3.0 12 | 13 | Platform: 14 | darwin x64 15 | 16 | npm manifest: 17 | { 18 | "name": "react-style-hoc", 19 | "version": "0.0.1", 20 | "description": "React higher order component - adds style related props to wrapped components", 21 | "main": "dist/index.js", 22 | "keywords": [ 23 | "react", 24 | "hoc", 25 | "style", 26 | "stylus", 27 | "'higher", 28 | "order", 29 | "component'", 30 | "props" 31 | ], 32 | "author": "kevin decock", 33 | "license": "ISC", 34 | "scripts": { 35 | "clear": "rimraf dist/**", 36 | "lint": "esw src", 37 | "lint:watch": "esw src -w", 38 | "test": "cross-env NODE_ENV=test mocha --compilers js:babel-core/register -t 2000 --recursive", 39 | "test:watch": "npm run test -- -w", 40 | "test:coverage": "nyc --reporter=lcov --reporter=text-summary npm test", 41 | "coverage:serve": "lite-server", 42 | "rollup": "rollup --config rollup.config.js", 43 | "build": "npm run rollup", 44 | "bundle": "npm-run-all -s lint build", 45 | "prepublish": "npm-run-all -s clear types bundle" 46 | }, 47 | "devDependencies": { 48 | "babel-cli": "^6.22.2", 49 | "babel-plugin-external-helpers": "^6.22.0", 50 | "babel-plugin-istanbul": "^3.1.2", 51 | "babel-plugin-rewire": "^1.0.0", 52 | "babel-plugin-transform-object-rest-spread": "^6.22.0", 53 | "babel-polyfill": "^6.22.0", 54 | "babel-preset-es2015": "^6.22.0", 55 | "babel-preset-es2015-rollup": "^3.0.0", 56 | "chai": "^3.5.0", 57 | "copy": "^0.3.0", 58 | "cross-env": "^3.1.4", 59 | "eslint": "^3.17.1", 60 | "eslint-watch": "^3.0.1", 61 | "istanbul": "^1.1.0-alpha.1", 62 | "lite-server": "^2.3.0", 63 | "mocha": "^3.2.0", 64 | "npm-run-all": "^4.0.2", 65 | "nyc": "^10.1.2", 66 | "rimraf": "^2.5.4", 67 | "rollup": "^0.41.4", 68 | "rollup-plugin-babel": "^2.7.1", 69 | "rollup-plugin-uglify": "^1.0.1", 70 | "sinon": "^1.17.7", 71 | "sinon-chai": "^2.8.0", 72 | "uglify-js": "github:mishoo/UglifyJS2#harmony" 73 | }, 74 | "nyc": { 75 | "include": [ 76 | "src/*.js" 77 | ], 78 | "require": [ 79 | "mocha", 80 | "babel-register", 81 | "babel-polyfill" 82 | ], 83 | "sourceMap": false, 84 | "instrument": false 85 | }, 86 | "repository": { 87 | "type": "git", 88 | "url": "" 89 | }, 90 | "engines": { 91 | "node": ">= 4.2.1", 92 | "npm": ">= 3" 93 | } 94 | } 95 | 96 | yarn manifest: 97 | No manifest 98 | 99 | Lockfile: 100 | No lockfile 101 | 102 | Trace: 103 | Error: getaddrinfo ENOTFOUND nexusrepo-z.antwerpen.be nexusrepo-z.antwerpen.be:443 104 | at errnoException (dns.js:28:10) 105 | at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:79:26) 106 | --------------------------------------------------------------------------------