├── .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 |
7 |
8 |
9 |
11 |
12 |
13 |
15 |
16 |
17 |
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 |
--------------------------------------------------------------------------------