├── .babelrc ├── .eslintrc ├── .gitignore ├── LICENSE ├── README.md ├── package.json ├── rollup.config.js └── src ├── Hide.js ├── LifeCycleAware.js ├── Promiser.js ├── Repeat.js ├── Show.js ├── Switch.js └── index.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false 5 | }], 6 | "stage-0", 7 | "react" 8 | ], 9 | "plugins": [ 10 | "external-helpers" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "standard", 5 | "standard-react" 6 | ], 7 | "env": { 8 | "es6": true 9 | }, 10 | "plugins": [ 11 | "react" 12 | ], 13 | "parserOptions": { 14 | "sourceType": "module", 15 | "allowImportExportEverywhere": true 16 | }, 17 | "rules": { 18 | "space-before-function-paren": 0, 19 | "react/jsx-boolean-value": 0, 20 | "import/first": 0 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # code editors 2 | .vscode 3 | 4 | # dependencies 5 | node_modules 6 | 7 | # builds 8 | build 9 | dist 10 | 11 | # misc 12 | .DS_Store 13 | .env 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | yarn.lock 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 MoroccanOSS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-stoon 2 | 3 |

4 | 5 | npm version 7 | 8 | 9 | license 11 | 12 | 13 | dependency status 15 | 16 | 17 | Join the chat at https://gitter.im/MoroccanOSS/react-stoon 19 | 20 |

21 | 22 | 23 | react-stoon is a handy toolbox of reusable Components that allow you to reduce boilerplate by writing less js inside of your React Components. 24 | 25 | 26 | react-stoon is a fast growing toolbox aspiring to be your lodash for React. 27 | 28 | ## Install 29 | 30 | ``` 31 | npm install react-stoon --save 32 | ``` 33 | 34 | 35 | ### Show 36 | 37 | renders `$` only if `if` is truthy. 38 | 39 | ```jsx 40 | const MyComponent = ({ shouldShowText }) => { 41 | return ( 42 | 43 | You can see this text, only if shouldShowText is truthy 44 | 45 | ); 46 | } 47 | ``` 48 | ### Hide 49 | 50 | hides `$` only if `if` is truthy. 51 | 52 | ```jsx 53 | const MyComponent = ({ shouldNotShowText }) => { 54 | return ( 55 | 56 | You can see this text, only if shouldNotShowText is false 57 | 58 | ); 59 | } 60 | ``` 61 | 62 | ### Repeat 63 | 64 | #### foearch 65 | 66 | creates a clone of `props.children` for each element of `props.foreach` while passing the current object as a prop with the alias defined by `as`. 67 | 68 | ```jsx 69 | const Book = ({children, book}) => { 70 | return ( 71 |
72 |
Book name {book}
73 |
74 | ) 75 | }; 76 | const books = ['Clean Code', 'Code Complete', 'The pragmatic programmer']; 77 | const MyComponent = () => { 78 | return ( 79 | 80 | 81 | 82 | ); 83 | } 84 | ``` 85 | 86 | #### times 87 | 88 | creates `times` copies of `props.children` while passing the index as a prop with the alias defined by `as`. 89 | 90 | ```jsx 91 | const MyDiv = ({children, index}) => { 92 | return ( 93 |
94 |
Element Number {index}
95 |
{children}
96 |
97 | ) 98 | }; 99 | const MyComponent = () => { 100 | return ( 101 | 102 | 103 | 104 | ); 105 | } 106 | ``` 107 | 108 | ### Switch 109 | 110 | renders `Switch.Case` if `value` matches `target`, renders `Switch.Default` if none matched. 111 | 112 | ```jsx 113 | const MyComponent = () => { 114 | return ( 115 | 116 | 117 | It's hey! 118 | 119 | 120 | It's hello! 121 | 122 | 123 | It's neither hey nor hello ! 124 | 125 | 126 | ); 127 | } 128 | ``` 129 | 130 | ### LifeCycleAware 131 | 132 | allows you to use React's lifecycle Hooks without turning your component to a class. 133 | 134 | ```jsx 135 | const MyComponent = () => { 136 | return ( 137 | console.log('Will Mount!')} 139 | didMount={() => console.log('Did Mount!')} 140 | > 141 | Hello, I am a LifecycleAwareComponent! 142 | 143 | ); 144 | } 145 | ``` 146 | 147 | 148 | ### Promiser 149 | 150 | ```jsx 151 | 152 | const MyComponent = () => { 153 | return ( 154 | } 157 | promise={getUser("younesshakky")} 158 | catch={err => } 159 | render={user => } 160 | /> 161 | ); 162 | } 163 | ``` 164 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-stoon", 3 | "version": "1.3.0", 4 | "description": "handy toolbox of reusable React Components", 5 | "author": "Amine Hakkou", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git@github.com:MoroccanOSS/react-stoon.git" 10 | }, 11 | "main": "dist/index.js", 12 | "module": "dist/index.es.js", 13 | "jsnext:main": "dist/index.es.js", 14 | "scripts": { 15 | "build": "rollup -c", 16 | "start": "rollup -c -w", 17 | "prepublish": "npm run build" 18 | }, 19 | "peerDependencies": { 20 | "react": "^0.14.9 || ^15.0.0 || ^16.0.0" 21 | }, 22 | "devDependencies": { 23 | "babel-core": "^6.26.0", 24 | "babel-eslint": "^8.2.1", 25 | "babel-plugin-external-helpers": "^6.22.0", 26 | "babel-preset-env": "^1.6.0", 27 | "babel-preset-react": "^6.24.1", 28 | "babel-preset-stage-0": "^6.24.1", 29 | "gh-pages": "^1.1.0", 30 | "react": "^16.2.0", 31 | "react-scripts": "^1.1.1", 32 | "rollup": "^0.54.0", 33 | "rollup-plugin-babel": "^3.0.3", 34 | "rollup-plugin-commonjs": "^8.2.1", 35 | "rollup-plugin-node-resolve": "^3.0.2", 36 | "rollup-plugin-peer-deps-external": "^2.0.0", 37 | "rollup-plugin-url": "^1.3.0" 38 | }, 39 | "files": [ 40 | "dist" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel' 2 | import commonjs from 'rollup-plugin-commonjs' 3 | import external from 'rollup-plugin-peer-deps-external' 4 | import resolve from 'rollup-plugin-node-resolve' 5 | import url from 'rollup-plugin-url' 6 | 7 | import pkg from './package.json' 8 | 9 | export default { 10 | input: 'src/index.js', 11 | output: [ 12 | { 13 | file: pkg.main, 14 | format: 'cjs', 15 | sourcemap: true 16 | }, 17 | { 18 | file: pkg.module, 19 | format: 'es', 20 | sourcemap: true 21 | } 22 | ], 23 | plugins: [ 24 | external(), 25 | url(), 26 | babel({ 27 | exclude: 'node_modules/**' 28 | }), 29 | resolve(), 30 | commonjs() 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /src/Hide.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default (props) => { 4 | const { if: invisible, children } = props; 5 | return (invisible)? null : children; 6 | } -------------------------------------------------------------------------------- /src/LifeCycleAware.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class LifeCycleAware extends React.Component { 4 | 5 | constructor(props) { 6 | super(props); 7 | const { construct, willMount, didMount, willUnmount } = props; 8 | this.construct = construct; 9 | this.willMount = willMount; 10 | this.didMount = didMount; 11 | this.willUnmount = willUnmount; 12 | 13 | this.construct && this.construct(); 14 | } 15 | 16 | componentDidMount() { 17 | return this.didMount && this.didMount(); 18 | } 19 | 20 | componentWillMount() { 21 | return this.willMount && this.willMount(); 22 | } 23 | 24 | componentWillUnmount() { 25 | return this.willUnmount && this.willUnmount(); 26 | } 27 | 28 | render() { 29 | return this.props.children; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Promiser.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | 3 | class Promiser extends Component { 4 | state = { 5 | result: null, 6 | isError: false, 7 | error: null, 8 | pending: true 9 | }; 10 | 11 | componentDidMount() { 12 | this.props.promise 13 | .then(data => { 14 | this.setState({ result: data, pending: false }); 15 | }) 16 | .catch(err => { 17 | this.setState({ 18 | isError: true, 19 | pending: false, 20 | error: err 21 | }); 22 | }); 23 | } 24 | 25 | render() { 26 | const { result, isError, error, pending } = this.state; 27 | const { preload, preloadComponent, render, catch: throwError } = this.props; 28 | 29 | if (preload && pending) { 30 | return preloadComponent || "loading..."; 31 | } 32 | 33 | return !isError && result ? render(result) : throwError(error); 34 | } 35 | } 36 | 37 | export default Promiser; 38 | -------------------------------------------------------------------------------- /src/Repeat.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class Repeat extends React.Component { 4 | 5 | render() { 6 | const { times, foreach, as, children } = this.props; 7 | if(times && foreach) { 8 | console.log('please make sure to specify either times or foreach'); 9 | } 10 | if(times) { 11 | return ( 12 | 13 | {children} 14 | 15 | ); 16 | } else if(foreach) { 17 | return ( 18 | 19 | {children} 20 | 21 | ); 22 | } else { 23 | return null; 24 | } 25 | } 26 | 27 | static Foreach({ $ = [], as = 'el', children }) { 28 | return $.map( 29 | (el) => React.Children.map( 30 | children, 31 | (child) => { 32 | const additionalProps = {}; 33 | additionalProps[as] = el; 34 | return React.cloneElement(child, additionalProps); 35 | } 36 | ) 37 | ); 38 | } 39 | 40 | static Times({ $, as = 'el', children }) { 41 | const arr = [...Array($)].map((el, index) => index); 42 | return ( 43 | 44 | {children} 45 | 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Show.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default (props) => { 4 | const { if: visible, children } = props; 5 | return (visible)? children : null; 6 | } -------------------------------------------------------------------------------- /src/Switch.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class Switch extends React.Component { 4 | render() { 5 | const { target, children = [] } = this.props; 6 | const defaultCase = children.filter( 7 | child => (child.type === Switch.Default) 8 | ); 9 | const cases = children.filter( 10 | child => ((child.type === Switch.Case) && (child.props.value === target)) 11 | ); 12 | return (cases.length)? cases : defaultCase; 13 | } 14 | 15 | static Case({ children }) { 16 | return children; 17 | } 18 | static Default({ children }) { 19 | return children; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export { default as LifeCycleAware } from './LifeCycleAware'; 2 | export { default as Repeat } from './Repeat'; 3 | export { default as Show } from './Show'; 4 | export { default as Switch } from './Switch'; 5 | export { default as Promiser } from './Promiser'; 6 | export { default as Hide } from './Hide'; 7 | 8 | --------------------------------------------------------------------------------