├── .babelrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── ToggleDisplay.jsx ├── __tests__ └── ToggleDisplay-test.js ├── package-lock.json └── package.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react"], 3 | "plugins": ["@babel/plugin-proposal-class-properties"] 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.jsx 2 | __tests__ 3 | *.md 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "6.1" 5 | 6 | install: 7 | - npm install 8 | 9 | script: 10 | - npm test 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | MIT License 3 | 4 | Copyright (c) 2018 Cameron Nokes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-toggle-display 2 | 3 | [![Build Status](https://travis-ci.org/ccnokes/react-toggle-display.svg?branch=master)](https://travis-ci.org/ccnokes/react-toggle-display) 4 | 5 | A stateless react component that toggles the display of it's children. It's like `ng-show`, `ng-hide` or `ng-if` but for react. 6 | 7 | This allows you to DRY up statements like this: 8 | 9 | ```javascript 10 |
11 | ``` 12 | 13 | Example usage: 14 | 15 | ```javascript 16 | import React, { Component } from 'react'; 17 | import ToggleDisplay from 'react-toggle-display'; 18 | 19 | class App extends Component { 20 | constructor() { 21 | super(); 22 | this.state = { show: false }; 23 | } 24 | 25 | handleClick() { 26 | this.setState({ 27 | show: !this.state.show 28 | }); 29 | } 30 | 31 | render() { 32 | return ( 33 |
34 |

35 | 36 |

37 | 38 | I am rendered in a span (by default) and hidden with display:none when show is false. 39 | 40 | 41 | 42 | I am rendered in a section and removed from the DOM when if is false. 43 | 44 |
45 | ); 46 | } 47 | } 48 | 49 | export default App; 50 | 51 | ``` 52 | [View demo](https://jsfiddle.net/ccnokes/oqttsu83/) 53 | 54 | 55 | ## Props 56 | 57 | `hide` - boolean 58 | 59 | `show` - boolean 60 | 61 | `if` - boolean 62 | 63 | `tag` - string. The tag name to use as the ToggleDisplay element. Defaults to span. 64 | 65 | The two first props are simply the inverse of each other. Using both at the same time will result in canceling each other out. 66 | 67 | 68 | ## Install 69 | 70 | ``` 71 | npm install react-toggle-display 72 | ``` 73 | 74 | ## Tests 75 | 76 | To run tests: `npm test` 77 | 78 | 79 | 80 | ## Contributors 81 | 82 | Big thanks to [willgm](https://github.com/willgm) for his contributions. 83 | 84 | 85 | ## Change Notes 86 | 87 | Note that if you are using a version under 0.1.1, you will have to compile react-toggle-display's JSX yourself. I recommend just updating to 1.x so you don't have to worry about that. No breaking API changes in 1.x. 88 | 89 | While v2 does not change anything functionally, it was refactored to be a ["stateless functional component"](https://facebook.github.io/react/blog/2015/10/07/react-v0.14.html#stateless-functional-components), which won't work in React versions less than 0.14. 90 | 91 | v2.2 adds the `prop-types` package to get rid of some warnings when using React 15.5 92 | 93 | -------------------------------------------------------------------------------- /ToggleDisplay.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | ToggleDisplay.propTypes = { 5 | tag: PropTypes.string, 6 | hide: PropTypes.bool, 7 | show: PropTypes.bool, 8 | if: PropTypes.bool 9 | }; 10 | 11 | ToggleDisplay.defaultProps = { 12 | tag: 'span' 13 | }; 14 | 15 | const propsToRemove = Object.keys(ToggleDisplay.propTypes); 16 | 17 | function isDefined(val) { 18 | return val != null; 19 | } 20 | 21 | function shouldHide(props) { 22 | if(isDefined(props.show)) { 23 | return !props.show; 24 | } 25 | else if(isDefined(props.hide)) { 26 | return props.hide; 27 | } 28 | return false; 29 | } 30 | 31 | function pickProps(props) { 32 | const newProps = Object.assign({}, props); 33 | propsToRemove.forEach(prop => { 34 | if(prop in newProps) { 35 | delete newProps[prop]; 36 | } 37 | }); 38 | return newProps; 39 | } 40 | 41 | export default function ToggleDisplay(props) { 42 | if(props.if === false) { 43 | return null; 44 | } 45 | 46 | let style = {}; 47 | if(shouldHide(props)) { 48 | style.display = 'none'; 49 | } 50 | 51 | const Tag = props.tag; 52 | // prevent our props from being leaked down onto the children 53 | const newProps = pickProps(props); 54 | 55 | return ( 56 | 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /__tests__/ToggleDisplay-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import reactDom from 'react-dom/server'; 3 | import test from 'tape'; 4 | import dom from 'cheerio'; 5 | import ToggleDisplay from '../ToggleDisplay.jsx'; 6 | 7 | const render = reactDom.renderToStaticMarkup; 8 | 9 | test('ToggleDisplay', t => { 10 | let el = 11 | 12 |

test

13 |
; 14 | let $ = dom.load(render(el)); 15 | 16 | let hasP = $('p').length > 0; 17 | t.equal(true, hasP, 'should be a

in the DOM'); 18 | t.end(); 19 | }); 20 | 21 | test('ToggleDisplay should hide it\'s children', t => { 22 | let el = 23 | 24 |

test

25 | ; 26 | let $ = dom.load(render(el)); 27 | 28 | 29 | let isHidden = $('span').css('display') === 'none'; 30 | t.equal(true, isHidden, 'should be a display:none prop on the '); 31 | t.end(); 32 | }); 33 | 34 | test('ToggleDisplay should conditionally render it\'s children (true)', t => { 35 | let el = 36 | 37 |

test

38 |
; 39 | let $ = dom.load(render(el)); 40 | 41 | let isInDOM = $.html().length > 0; 42 | t.equal(true, isInDOM, 'should exist in DOM'); 43 | t.end(); 44 | }); 45 | 46 | test('ToggleDisplay should conditionally render it\'s children (false)', t => { 47 | let el = 48 | 49 |

test

50 |
; 51 | let $ = dom.load(render(el)); 52 | 53 | let hasP = $('p').length > 0; 54 | let hasSpan = $('span').length > 0; 55 | t.equal(false, hasP, 'should not be a

'); 56 | t.equal(false, hasSpan, 'should not be a '); 57 | t.end(); 58 | }); 59 | 60 | test('ToggleDisplay should render with the specified tag name with as the default', t => { 61 | let el = 62 | 63 |

test

64 | ; 65 | 66 | let el2 = 67 | 68 |

test

69 |
; 70 | 71 | let $ = dom.load(render(el)); 72 | let $2 = dom.load(render(el2)); 73 | 74 | let hasAside = $('aside').length > 0; 75 | let noAside = $2('aside').length > 0; 76 | let hasSpan = $2('span').length > 0; 77 | 78 | t.equal(true, hasAside, 'should be an