├── .babelrc ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmignore ├── CHANGELOG.md ├── README.md ├── build ├── webpack.config.js └── webpack │ ├── base.js │ ├── development.js │ └── production.js ├── config └── index.js ├── development ├── App.js ├── client.js ├── containers │ └── DevTools.js ├── index.less ├── largetext.js ├── reducer.js └── store.js ├── package.json └── src ├── Modal.js ├── ReduxModal.js ├── emitter.js ├── index.js ├── less └── index.less ├── redux.js └── utils.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "syntax-class-properties", 4 | "transform-class-properties", 5 | "transform-decorators-legacy", 6 | "transform-es2015-arrow-functions", 7 | "transform-es2015-block-scoping", 8 | ["transform-es2015-classes", {"loose": true}], 9 | "transform-proto-to-assign" 10 | ], 11 | "presets": ["stage-0", "react", "es2015"] 12 | } 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | lib 2 | node_modules 3 | demo 4 | .DS_Store -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "browser": true, 5 | "node": true 6 | }, 7 | "ecmaFeatures": { 8 | "jsx": true 9 | }, 10 | "plugins": [ 11 | "react" 12 | ], 13 | "rules": { 14 | "comma-dangle": [2, "never"], 15 | "no-cond-assign": 2, 16 | "no-constant-condition": 2, 17 | "no-control-regex": 2, 18 | "no-debugger": 2, 19 | "no-dupe-keys": 2, 20 | "no-empty": 2, 21 | "no-empty-character-class": 2, 22 | "no-ex-assign": 2, 23 | "no-extra-boolean-cast": 2, 24 | "no-extra-parens": 0, 25 | "no-extra-semi": 2, 26 | "no-func-assign": 2, 27 | "no-inner-declarations": 2, 28 | "no-invalid-regexp": 2, 29 | "no-irregular-whitespace": 2, 30 | "no-negated-in-lhs": 2, 31 | "no-obj-calls": 2, 32 | "no-regex-spaces": 2, 33 | "no-reserved-keys": 0, 34 | "no-sparse-arrays": 2, 35 | "no-unreachable": 2, 36 | "strict": [2, "global"], 37 | "no-catch-shadow": 2, 38 | "no-delete-var": 2, 39 | "no-label-var": 2, 40 | "no-shadow": 2, 41 | "no-shadow-restricted-names": 2, 42 | "no-undef": 2, 43 | "no-undef-init": 2, 44 | "no-undefined": 2, 45 | "no-unused-vars": 2, 46 | "no-use-before-define": 2, 47 | "indent": [2, 2, { 48 | "SwitchCase": 1 49 | }], 50 | "brace-style": 2, 51 | "camelcase": 0, 52 | "comma-spacing": 2, 53 | "comma-style": 2, 54 | "consistent-this": 0, 55 | "eol-last": 2, 56 | "func-names": 0, 57 | "func-style": 0, 58 | "key-spacing": [2, { 59 | "beforeColon": false, 60 | "afterColon": true 61 | }], 62 | "max-nested-callbacks": 0, 63 | "new-cap": 2, 64 | "new-parens": 2, 65 | "no-array-constructor": 2, 66 | "no-inline-comments": 0, 67 | "no-lonely-if": 2, 68 | "no-mixed-spaces-and-tabs": 2, 69 | "no-nested-ternary": 2, 70 | "no-new-object": 2, 71 | "semi-spacing": [2, { 72 | "before": false, 73 | "after": true 74 | }], 75 | "no-spaced-func": 2, 76 | "no-ternary": 0, 77 | "no-trailing-spaces": 2, 78 | "no-multiple-empty-lines": 2, 79 | "no-underscore-dangle": 0, 80 | "one-var": 0, 81 | "operator-assignment": [2, "always"], 82 | "padded-blocks": 0, 83 | "quotes": [2, "single"], 84 | "quote-props": [2, "as-needed"], 85 | "semi": [2, "always"], 86 | "sort-vars": [2, {"ignoreCase": true}], 87 | "space-after-keywords": 2, 88 | "space-before-blocks": 2, 89 | "object-curly-spacing": [2, "never"], 90 | "array-bracket-spacing": [2, "never"], 91 | "space-in-parens": 2, 92 | "space-infix-ops": 2, 93 | "space-return-throw-case": 2, 94 | "space-unary-ops": 2, 95 | "spaced-comment": 2, 96 | "wrap-regex": 0, 97 | "use-isnan": 2, 98 | "valid-jsdoc": 0, 99 | "valid-typeof": 2, 100 | "react/display-name": 1, 101 | "react/jsx-no-undef": 1, 102 | "react/jsx-uses-react": 1, 103 | "react/jsx-uses-vars": 1 104 | } 105 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | 0.* 4 | 1.* 5 | lib 6 | fonts/ 7 | dist 8 | typings/ 9 | tsconfig.json -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | ._* 3 | .DS_Store 4 | .git 5 | .hg 6 | .npmrc 7 | .lock-wscript 8 | .svn 9 | .wafpickle-* 10 | config.gypi 11 | CVS 12 | npm-debug.log 13 | src 14 | CHANGELOG.md 15 | build/ 16 | config/ 17 | node_modules 18 | .babelrc 19 | .eslintrc 20 | .tsconfig.json 21 | .gitignore 22 | .eslintigore 23 | dist/ 24 | typings/ -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diegoddox/react-redux-modal/d0301457df2c31e0476935f8511c0869760a1180/CHANGELOG.md -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NOT MAINTAINED 2 | 3 | ##`react-redux-modal` [demo](http://diegoddox.github.io/react-redux-modal/) 4 | 5 | ## Implementation Guide 6 | 7 | ##### 1. Installation 8 | 9 | `npm install --save react-redux-modal` 10 | 11 | ##### 2. Add the `react-redux-modal` css link to your app 12 | ``` 13 | 14 | ``` 15 | ##### 3. The third thing you need to do is to add the `react-redux-modal` `reducer` to Redux. 16 | 17 | ``` 18 | import {createStore, combineReducers} from 'redux' 19 | import {reducer as modalReducer} from 'react-redux-modal' 20 | const reducers = { 21 | // ... other reducers ... 22 | modals: modalReducer // <- Mounted at modals. 23 | } 24 | const reducer = combineReducers(reducers) 25 | const store = createStore(reducer) 26 | ``` 27 | 28 | ##### NOTE: The default mount point for `react-redux-modal` is `modals`. 29 | 30 | ##### 4. Add the `react-redux-modal` React component to the root of your app 31 | ``` 32 | import {Provider} from 'react-redux' 33 | import ReduxModal from 'react-redux-modal' 34 | 35 | 36 |
37 | ... other things like router ... 38 | 39 |
40 |
41 | ``` 42 | 43 | ##### 5. Add the `react-redux-modal` `modal` emitter 44 | The `modal` method use [eventemitter3](https://github.com/primus/eventemitter3) to dispatch the actions 45 | 46 | ``` 47 | import React, {Component} from 'react' 48 | import {modal} from 'react-redux-modal' // The modal emitter 49 | ``` 50 | 51 | Create a `component` that will be injected in the modal 52 | ``` 53 | class myModalComopnent extends Component { 54 | constructor(props) { 55 | super(props); 56 | console.log('## MODAL DATA AND PROPS:', this.props); 57 | } 58 | 59 | removeThisModal() { 60 | this.props.removeModal(); 61 | } 62 | 63 | render() { 64 | return ( 65 |
66 |

this is my modal

67 | 72 |
73 | ); 74 | } 75 | } 76 | ``` 77 | ``` 78 | export class YourComponent extends Component { 79 | constructor(props) { 80 | super(props); 81 | } 82 | 83 | addModal() { 84 | modal.add(myModalComopnent, { 85 | title: 'This is my modal', 86 | size: 'medium', // large, medium or small, 87 | closeOnOutsideClick: false // (optional) Switch to true if you want to close the modal by clicking outside of it, 88 | hideTitleBar: false // (optional) Switch to true if do not want the default title bar and close button, 89 | hideCloseButton: false // (optional) if you don't wanna show the top right close button 90 | //.. all what you put in here you will get access in the modal props ;) 91 | }); 92 | } 93 | 94 | render() { 95 | return ; 96 | } 97 | } 98 | ``` 99 | 100 | The `modal` `add` method takes two arguments, first a `react` `component` and a `object` that will specify the modal `title`, `size` and `data` 101 | 102 | # Run a local demo 103 | ``` 104 | git clone https://github.com/diegoddox/react-redux-modal.git 105 | cd react-redux-modal 106 | npm install 107 | npm start 108 | ``` 109 | open your browser at `http://localhost:3001` 110 | 111 | # TODO 112 | create test. -------------------------------------------------------------------------------- /build/webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = require('./webpack/' + require('../config').env); 4 | -------------------------------------------------------------------------------- /build/webpack/base.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var webpack = require('webpack'); 4 | var path = require('path'); 5 | var HtmlWebpackPlugin = require('html-webpack-plugin'); 6 | var config = require('../../config'); 7 | 8 | // const baseSrcPath = path.join(config.path_base, '/' + config.dir_client); 9 | 10 | module.exports = { 11 | target: 'web', 12 | entry: { 13 | app: path.join(config.path_base, '/' + config.dir_client + '/client.js') 14 | }, 15 | output: { 16 | path: path.join(config.path_base + '/dist'), 17 | filename: 'bundle.js', 18 | publicPath: '' 19 | }, 20 | module: { 21 | preLoaders: [ 22 | { 23 | test: /\.jsx?$/, 24 | loaders: ['eslint'], 25 | exclude: /node_modules/ 26 | } 27 | ], 28 | loaders: [ 29 | { 30 | test: /\.js?$/, 31 | exclude: /node_modules/, 32 | loaders: ['react-hot', 'babel'] 33 | }, { 34 | test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/, 35 | exclude: /node_modules/, 36 | loader: 'url-loader' 37 | }, { 38 | test: /\.less$/, 39 | exclude: /node_modules/, 40 | loader: 'style!css!less' 41 | }, { 42 | test: /\.css$/, 43 | loader: 'style-loader!css-loader' 44 | }, { 45 | test: /\.jpg$/, 46 | exclude: /node_modules/, 47 | loader: 'file-loader' 48 | } 49 | ] 50 | }, 51 | plugins: [ 52 | new webpack.DefinePlugin({ 53 | 'process.env': { 54 | NODE_ENV: '"' + process.env.NODE_ENV + '"' 55 | } 56 | }), 57 | new HtmlWebpackPlugin({ 58 | templateContent: '' 59 | + '' 60 | + '' 61 | + ' ' 62 | + ' ' 63 | + ' React Redux Modal' 64 | + ' ' 65 | + ' ' 66 | + ' ' 67 | + ' ' 68 | + ' ' 69 | + '
' 70 | + ' ' 71 | + '', 72 | inject: 'body' 73 | }) 74 | ] 75 | }; 76 | -------------------------------------------------------------------------------- /build/webpack/development.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var config = require('../../config'); 5 | var baseConfig = require('./base'); 6 | 7 | baseConfig.entry.app = [ 8 | 'webpack-dev-server/client?http://localhost:' + config.server_port, 9 | 'webpack/hot/only-dev-server', 10 | config.path_base + '/' + config.dir_client + '/client.js' 11 | ]; 12 | 13 | baseConfig.devtool = 'inline-source-map'; 14 | 15 | baseConfig.devServer = { 16 | headers: { 17 | 'Access-Control-Allow-Origin': '*', 18 | 'Access-Control-Allow-Credentials': true, 19 | 'Access-Control-Max-Age': 1 20 | }, 21 | contentBase: path.join(config.path_base, '/' + config.dir_client), 22 | noInfo: false, 23 | port: config.server_port, 24 | hot: true, 25 | stats: { 26 | colors: true 27 | }, 28 | historyApiFallback: true 29 | }; 30 | 31 | module.exports = baseConfig; 32 | -------------------------------------------------------------------------------- /build/webpack/production.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var webpack = require('webpack'); 4 | var webpackBase = require('./base'); 5 | 6 | webpackBase.plugins.push( 7 | new webpack.optimize.UglifyJsPlugin({ 8 | compress: { 9 | warnings: false 10 | } 11 | }) 12 | ); 13 | 14 | module.exports = webpackBase; 15 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | 5 | module.exports = { 6 | env: process.env.NODE_ENV, 7 | path_base: path.resolve(__dirname, '../'), 8 | dir_client: 'development', 9 | server_port: process.env.NODE_PORT || 3000 10 | }; 11 | -------------------------------------------------------------------------------- /development/App.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import './index.less'; 4 | import './../src/less/index.less'; 5 | import React, {Component, PropTypes} from 'react'; 6 | import {Provider} from 'react-redux'; 7 | import ReduxModal, {modal} from './../src/'; 8 | import DevTools from './containers/DevTools'; 9 | import largeText from './largetext'; 10 | import config from './../config'; 11 | 12 | import loremIpsum from 'lorem-ipsum'; 13 | 14 | class myLargeModalComponent extends Component { 15 | static displayName = 'MySUperModal'; 16 | 17 | constructor(props) { 18 | super(props); 19 | console.log('##myLargeModalComponent props##', this.props); 20 | } 21 | 22 | render() { 23 | return ( 24 |
25 |

{loremIpsum({count: 1})}

26 | 29 |
30 | ); 31 | } 32 | } 33 | 34 | class modalComponentWithButton extends Component { 35 | static displayName = 'MySUperModal'; 36 | 37 | render() { 38 | return ( 39 |
40 |

{loremIpsum({count: 1})}

41 | 44 |
45 | ); 46 | } 47 | } 48 | 49 | class modalComponent extends Component { 50 | static displayName = 'MySUperModal'; 51 | 52 | render() { 53 | return

{largeText}

; 54 | } 55 | } 56 | 57 | class myModalComponent extends Component { 58 | static displayName = 'MySUperModal'; 59 | 60 | render() { 61 | return

:D {largeText}

; 62 | } 63 | } 64 | 65 | export default class App extends Component { 66 | static displayName = 'ReduxModalDev'; 67 | 68 | static propTypes = { 69 | store: PropTypes.object.isRequired 70 | }; 71 | 72 | constructor(props) { 73 | super(props); 74 | this.renderDev = this.renderDev.bind(this); 75 | } 76 | 77 | addModalLarge() { 78 | modal.add(myLargeModalComponent, { 79 | title: 'This one there is no close botton.', 80 | size: 'large', 81 | hideCloseButton: true 82 | }); 83 | } 84 | 85 | addModalMedium() { 86 | modal.add(myModalComponent, { 87 | title: 'Time to get some food', 88 | size: 'medium' 89 | }); 90 | } 91 | 92 | addModalSmall() { 93 | modal.add(modalComponent, { 94 | title: 'You got it', 95 | size: 'small' 96 | }); 97 | } 98 | 99 | addOutsideClickCloseModal() { 100 | modal.add(modalComponent, { 101 | title: 'You got it', 102 | size: 'small', 103 | closeOnOutsideClick: true 104 | }); 105 | } 106 | addModalWithoutTitle() { 107 | modal.add(modalComponentWithButton, { 108 | title: null, 109 | hideTitleBar: true, 110 | size: 'small' 111 | }); 112 | } 113 | 114 | renderDev() { 115 | if (config.env !== 'production') { 116 | return ; 117 | } 118 | } 119 | 120 | render() { 121 | return ( 122 | 123 |
124 |
125 | 128 | 131 | 132 | 135 | 138 | 141 |
142 | 143 | {this.renderDev()} 144 |
145 |
146 | ); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /development/client.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import React from 'react'; 3 | import {render} from 'react-dom'; 4 | import createStore from './store'; 5 | import App from './App'; 6 | 7 | const store = createStore(); 8 | const target = document.getElementById('app'); 9 | 10 | render(, target); 11 | -------------------------------------------------------------------------------- /development/containers/DevTools.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react'; 4 | import {createDevTools} from 'redux-devtools'; 5 | import LogMonitor from 'redux-devtools-log-monitor'; 6 | import DockMonitor from 'redux-devtools-dock-monitor'; 7 | 8 | export default createDevTools( 9 | 12 | 13 | 14 | ); 15 | -------------------------------------------------------------------------------- /development/index.less: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | width: 70%; 3 | margin: 100px auto; 4 | 5 | .content { 6 | width: 100%; 7 | text-align: center; 8 | button { 9 | margin: 20px; 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /development/largetext.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | const text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis vitae aliquam lacus. Donec a egestas mauris. Quisque et luctus nisi, vel placerat est. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus tincidunt ullamcorper eros, nec tincidunt sapien ultrices in. Vestibulum sed blandit mi. Pellentesque augue tellus, bibendum id nulla vitae, consequat bibendum purus. Cras varius tellus a convallis finibus. Praesent sem risus, tristique at suscipit a, mattis id orci. Vestibulum interdum ligula sit amet ex lobortis, ac maximus ipsum vestibulum. Donec suscipit viverra nisl placerat imperdiet. Aliquam pulvinar ut orci id pharetra. Quisque tristique augue a dui efficitur ornare. Aenean tincidunt eget sem ut pulvinar. Quisque at ligula rhoncus, congue justo et, sagittis ex. Pellentesque sapien magna, porta ut pulvinar a, venenatis at turpis.Aenean ut mi a odio hendrerit laoreet. Morbi convallis, massa et tristique tempus, risus eros rhoncus turpis, vel accumsan velit purus nec urna. Curabitur varius molestie orci nec cursus. Curabitur pretium erat feugiat tortor imperdiet hendrerit. Curabitur condimentum cursus dui sit amet vestibulum. Nunc pretium iaculis est vel dignissim. Fusce et enim tempor, laoreet lacus in, hendrerit lectus. Sed sagittis sollicitudin condimentum. Curabitur fermentum dui at congue vehicula. Fusce vel risus sed lectus egestas ullamcorper. Morbi vel mauris erat.Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis vitae aliquam lacus. Donec a egestas mauris. Quisque et luctus nisi, vel placerat est. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus tincidunt ullamcorper eros, nec tincidunt sapien ultrices in. Vestibulum sed blandit mi. Pellentesque augue tellus, bibendum id nulla vitae, consequat bibendum purus. Cras varius tellus a convallis finibus. Praesent sem risus, tristique at suscipit a, mattis id orci. Vestibulum interdum ligula sit amet ex lobortis, ac maximus ipsum vestibulum. Donec suscipit viverra nisl placerat imperdiet. Aliquam pulvinar ut orci id pharetra. Quisque tristique augue a dui efficitur ornare. Aenean tincidunt eget sem ut pulvinar. Quisque at ligula rhoncus, congue justo et, sagittis ex. Pellentesque sapien magna, porta ut pulvinar a, venenatis at turpis.Aenean ut mi a odio hendrerit laoreet. Morbi convallis, massa et tristique tempus, risus eros rhoncus turpis, vel accumsan velit purus nec urna. Curabitur varius molestie orci nec cursus. Curabitur pretium erat feugiat tortor imperdiet hendrerit. Curabitur condimentum cursus dui sit amet vestibulum. Nunc pretium iaculis est vel dignissim. Fusce et enim tempor, laoreet lacus in, hendrerit lectus. Sed sagittis sollicitudin condimentum. Curabitur fermentum dui at congue vehicula. Fusce vel risus sed lectus egestas ullamcorper. Morbi vel mauris erat'; 5 | 6 | export default text; 7 | -------------------------------------------------------------------------------- /development/reducer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import {combineReducers} from 'redux'; 3 | import {reducer as modalReducer} from './../src/'; 4 | export default combineReducers({ 5 | modals: modalReducer 6 | }); 7 | -------------------------------------------------------------------------------- /development/store.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react'; // eslint-disable-line no-unused-vars 4 | import {createStore, compose} from 'redux'; 5 | import DevTools from './containers/DevTools'; 6 | import rootReducers from './reducer'; 7 | 8 | export default function configStore(initialState) { 9 | let createStoreWithMiddleware; 10 | createStoreWithMiddleware = compose(DevTools.instrument()); 11 | 12 | const store = createStoreWithMiddleware(createStore)(rootReducers, initialState); 13 | 14 | // This we only use in development. 15 | if (module.hot) { 16 | module.hot.accept('./reducer', () => { 17 | const nextRootReducers = require('./reducer'); 18 | store.replaceReducer(nextRootReducers); 19 | }); 20 | } 21 | 22 | return store; 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-redux-modal", 3 | "version": "0.5.2", 4 | "description": "react-redux-modal is a React modal implemented with Redux", 5 | "main": "lib/index.js", 6 | "jsnext:main": "./src/index.js", 7 | "scripts": { 8 | "start": "better-npm-run dev-server", 9 | "build:w": "better-npm-run build:w", 10 | "build": "better-npm-run build && npm run less && npm run less:m", 11 | "less": "node_modules/.bin/lessc src/less/index.less --autoprefix=\"last 2 versions\" lib/css/react-redux-modal.css", 12 | "less:m": "node_modules/.bin/lessc src/less/index.less --autoprefix=\"last 2 versions\" --clean-css lib/css/react-redux-modal.min.css", 13 | "clean": "better-npm-run clean", 14 | "lint": "better-npm-run lint", 15 | "build_app": "concurrent --kill-others & npm run clean & npm run lint & npm run build & npm run less & npm run less:m", 16 | "buildc": "better-npm-run build_client" 17 | }, 18 | "eslintConfig": { 19 | "root": true 20 | }, 21 | "betterScripts": { 22 | "dev-server": { 23 | "command": "./node_modules/.bin/webpack-dev-server --hot --inline --config build/webpack.config.js", 24 | "env": { 25 | "NODE_ENV": "development", 26 | "NODE_PORT": 3001 27 | } 28 | }, 29 | "build_client": { 30 | "command": "./node_modules/.bin/webpack --progress --config build/webpack.config.js", 31 | "env": { 32 | "NODE_ENV": "production" 33 | } 34 | }, 35 | "build": { 36 | "command": "node_modules/.bin/babel src/ --out-dir lib" 37 | }, 38 | "build:w": { 39 | "command": "node_modules/.bin/babel -w src/ --out-dir lib" 40 | }, 41 | "lint": { 42 | "command": "node_modules/.bin/eslint . --ext .js --ext .jsx || true" 43 | }, 44 | "clean": { 45 | "command": "node_modules/.bin/rimraf dist lib" 46 | } 47 | }, 48 | "author": "Diego Oliveira", 49 | "license": "MIT", 50 | "repository": { 51 | "type": "git", 52 | "url": "https://github.com/diegoddox/react-redux-modal" 53 | }, 54 | "bugs": { 55 | "url": "https://github.com/diegoddox/react-redux-modal/issues" 56 | }, 57 | "files": [ 58 | "lib/", 59 | "src/", 60 | "CHANGELOG.md", 61 | "README.md" 62 | ], 63 | "keywords": [ 64 | "React.js", 65 | "React", 66 | "Redux", 67 | "react", 68 | "redux modal", 69 | "react-redux-modal", 70 | "react-component", 71 | "modal", 72 | "react modal", 73 | "react redux modal", 74 | "react modal redux" 75 | ], 76 | "devDependencies": { 77 | "babel-cli": "^6.6.5", 78 | "babel-core": "^6.2.1", 79 | "babel-eslint": "^4.1.6", 80 | "babel-loader": "^6.2.0", 81 | "babel-plugin-syntax-class-properties": "^6.1.18", 82 | "babel-plugin-transform-class-properties": "^6.2.2", 83 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 84 | "babel-plugin-transform-es2015-arrow-functions": "^6.1.18", 85 | "babel-plugin-transform-es2015-block-scoping": "^6.1.18", 86 | "babel-plugin-transform-proto-to-assign": "^6.6.5", 87 | "babel-preset-es2015": "^6.1.18", 88 | "babel-preset-react": "^6.1.18", 89 | "babel-preset-stage-0": "^6.1.18", 90 | "better-npm-run": "0.0.4", 91 | "chance": "^0.8.0", 92 | "concurrently": "^1.0.0", 93 | "core-js": "^2.0.2", 94 | "css-loader": "^0.23.1", 95 | "eslint": "^1.10.1", 96 | "eslint-loader": "^1.1.1", 97 | "eslint-plugin-react": "^3.16.1", 98 | "html-webpack-plugin": "^1.6.2", 99 | "jasmine": "^2.3.2", 100 | "jshint": "^2.9.1-rc1", 101 | "jshint-loader": "^0.8.3", 102 | "karma": "^0.13.15", 103 | "karma-jasmine": "^0.3.6", 104 | "karma-phantomjs-launcher": "^0.2.1", 105 | "karma-webpack": "^1.7.0", 106 | "less": "^2.5.3", 107 | "less-loader": "^2.2.1", 108 | "less-plugin-autoprefix": "^1.5.1", 109 | "less-plugin-clean-css": "^1.5.1", 110 | "lorem-ipsum": "^1.0.3", 111 | "phantomjs": "^1.9.19", 112 | "phantomjs-polyfill": "0.0.1", 113 | "react": "^0.14.7", 114 | "react-dom": "^0.14.7", 115 | "react-hot-loader": "^1.3.0", 116 | "react-redux": "^4.4.0", 117 | "redux": "^3.3.1", 118 | "redux-devtools": "^3.1.1", 119 | "redux-devtools-dock-monitor": "^1.1.0", 120 | "redux-devtools-log-monitor": "^1.0.5", 121 | "redux-logger": "^2.0.4", 122 | "rimraf": "^2.4.4", 123 | "style-loader": "^0.13.0", 124 | "url-loader": "^0.5.7", 125 | "webpack": "^1.12.4", 126 | "webpack-dev-server": "^1.14.0" 127 | }, 128 | "dependencies": { 129 | "classnames": "^2.2.3", 130 | "eventemitter3": "^1.1.1", 131 | "uuid": "^2.0.1" 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/Modal.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, {Component, PropTypes} from 'react'; 4 | import classnames from 'classnames'; 5 | 6 | class Modal extends Component { 7 | constructor(props) { 8 | super(props); 9 | } 10 | 11 | handleOnOutsideClick(e) { 12 | if (this.props.options.closeOnOutsideClick && !this.isChildOf(e.target, this.refs.modalContent) || false) { 13 | this.props.removeModal(this.props.id); 14 | } 15 | } 16 | 17 | isChildOf(child, parent) { 18 | if (child.parentNode === parent) { 19 | return true; 20 | } else if (child.parentNode === null) { 21 | return false; 22 | } else { 23 | return this.isChildOf(child.parentNode, parent); 24 | } 25 | } 26 | 27 | render() { 28 | return ( 29 |
30 |
31 | 32 |
33 | {this.props.options.hideTitleBar ? null : 34 |
35 |

{this.props.options.title}

36 |
37 | {this.props.options.hideCloseButton ? null : 38 | 42 | } 43 |
44 |
45 | } 46 | 47 |
48 | this.props.removeModal(this.props.id)}/> 49 |
50 |
51 | 52 |
53 | 54 |
55 |
56 | ); 57 | } 58 | } 59 | 60 | Modal.displayName = 'rrModal'; 61 | 62 | Modal.propTypes = { 63 | id: PropTypes.string, 64 | index: PropTypes.number, 65 | removeModal: PropTypes.func.isRequired, 66 | options: PropTypes.shape({ 67 | size: PropTypes.string, 68 | title: PropTypes.string, 69 | hideCloseButton: PropTypes.bool, 70 | hideTitleBar: PropTypes.bool, 71 | closeOnOutsideClick: PropTypes.bool 72 | }).isRequired 73 | }; 74 | 75 | export default Modal; 76 | -------------------------------------------------------------------------------- /src/ReduxModal.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import React, {Component, PropTypes} from 'react'; 3 | import {connect} from 'react-redux'; 4 | import {EE} from './emitter'; 5 | import * as actions from './redux'; 6 | import Modal from './Modal'; 7 | 8 | @connect(state => ({modals: state.modals.modals}), actions) 9 | class ReduxModal extends Component { 10 | constructor(props) { 11 | super(props); 12 | } 13 | 14 | componentDidMount() { 15 | EE.on('add/modal', obj => this.props.addModal(obj)); 16 | EE.on('clear/all', this.props.clearAll); 17 | } 18 | 19 | componentWillUnmount() { 20 | EE.off('add/modal'); 21 | EE.off('clear/all'); 22 | } 23 | 24 | render() { 25 | return ( 26 |
27 |
28 | {this.props.modals.map((modal, i) => { 29 | return ( 30 | 35 | ); 36 | })} 37 |
38 |
39 | ); 40 | } 41 | } 42 | 43 | ReduxModal.displayName = 'ReduxModal'; 44 | 45 | ReduxModal.propTypes = { 46 | modals: PropTypes.array 47 | }; 48 | 49 | export default ReduxModal; 50 | -------------------------------------------------------------------------------- /src/emitter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import EventEmitter from 'eventemitter3'; 3 | const emitter = new EventEmitter(); 4 | 5 | export const EE = emitter; 6 | export const modalEmitter = { 7 | add: (component, options) => emitter.emit('add/modal', {component, options}), 8 | remove: id => emitter.emit('remove/modal', id), 9 | clear: () => emitter.emit('clear/all') 10 | }; 11 | 12 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import ReduxModal from './ReduxModal'; 4 | import reduxDuck from './redux'; 5 | import {modalEmitter} from './emitter'; 6 | import * as modalActions from './redux'; 7 | 8 | export default ReduxModal; 9 | export const reducer = reduxDuck; 10 | export const actions = modalActions; 11 | export const modal = modalEmitter; 12 | -------------------------------------------------------------------------------- /src/less/index.less: -------------------------------------------------------------------------------- 1 | .react-redux-modal { 2 | font-family: "Arial"; 3 | box-sizing: content-box; 4 | 5 | button { 6 | &:focus { 7 | outline: 0; 8 | } 9 | } 10 | 11 | .rrm-holder { 12 | width: 100%; 13 | height: 100%; 14 | position: fixed; 15 | top: 0; 16 | left: 0; 17 | 18 | .scroll { 19 | width: 100%; 20 | height: 100%; 21 | position: relative; 22 | overflow-y: auto; 23 | z-index: 1; 24 | 25 | .rrm-content { 26 | z-index: 1; 27 | background-color: #fcfcfc; 28 | position: relative; 29 | border-radius: 4px; 30 | box-shadow: 0px 0px 20px #333; 31 | margin: 80px auto; 32 | overflow: hidden; 33 | 34 | &.m-small { 35 | width: 300px; 36 | 37 | .rrm-title { 38 | h2 { 39 | width: 140px; 40 | } 41 | } 42 | } 43 | 44 | &.m-medium { 45 | width: 500px; 46 | .rrm-title { 47 | h2 { 48 | width: 340px; 49 | } 50 | } 51 | } 52 | 53 | &.m-large { 54 | width: 800px; 55 | .rrm-title { 56 | h2 { 57 | width: 640px; 58 | } 59 | } 60 | } 61 | 62 | .rrm-title { 63 | width: 100%; 64 | height: 60px; 65 | border-bottom: 1px solid #dbdbdb; 66 | position: relative; 67 | color: #444; 68 | box-sizing: content-box; 69 | 70 | h2 { 71 | height: 60px; 72 | padding: 0px 20px; 73 | white-space: nowrap; 74 | overflow: hidden; 75 | text-overflow: ellipsis; 76 | font-size: 1.4em; 77 | margin: 0; 78 | line-height: 60px; 79 | float: left; 80 | box-sizing: content-box; 81 | } 82 | 83 | .rr-title-actions { 84 | width: 120px; 85 | height: 100%; 86 | text-align: center; 87 | float: left; 88 | 89 | button { 90 | width: 40px; 91 | height: 40px; 92 | margin: 10px 8px; 93 | line-height: 40px; 94 | position: relative; 95 | border: 1px solid transparent; 96 | float: right; 97 | background-color: transparent; 98 | text-align: center; 99 | padding: 0; 100 | color: #666; 101 | font-size: 1.2em; 102 | border-radius: 50%; 103 | 104 | &:hover { 105 | color: #4186bf; 106 | cursor: pointer; 107 | background-color: rgba(65, 134, 191, .1); 108 | border-color: rgba(65, 134, 191, .2); 109 | box-shadow: 2px 2px 3px #f0f0f0; 110 | } 111 | } 112 | } 113 | } 114 | 115 | .rrm-body { 116 | width: 100%; 117 | padding: 20px; 118 | } 119 | } 120 | } 121 | 122 | .rrm-shadow { 123 | width: 100%; 124 | height: 100%; 125 | background-color: rgba(50,58,68, .8); 126 | position: absolute; 127 | top: 0; 128 | left: 0; 129 | z-index: 0; 130 | } 131 | } 132 | } -------------------------------------------------------------------------------- /src/redux.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import uiid from 'uuid'; 4 | import {createReducer} from './utils.js'; 5 | 6 | export const ADD_MODAL = '@react-redux-modal.ADD_MODAL'; 7 | export const REMOVE_MODAL = '@react-redux-modal.REMOVE_MODAL'; 8 | export const CLEAR_ALL = '@react-redux-modal.CLEAR_ALL'; 9 | 10 | const initialSate = { 11 | modals: [] 12 | }; 13 | 14 | export default createReducer(initialSate, { 15 | [ADD_MODAL]: (state, payload) => { 16 | return { 17 | ...state, 18 | modals: [ 19 | ...state.modals, 20 | { 21 | id: uiid.v1(), 22 | ...payload 23 | } 24 | ] 25 | }; 26 | }, 27 | [REMOVE_MODAL]: (state, id) => { 28 | return { 29 | ...state, 30 | modals: state.modals.filter(modal => modal.id !== id) 31 | }; 32 | }, 33 | [CLEAR_ALL]: () => { 34 | return { 35 | modals: [] 36 | }; 37 | } 38 | }); 39 | 40 | export function addModal(payload) { 41 | return { 42 | type: ADD_MODAL, 43 | payload: payload 44 | }; 45 | } 46 | 47 | export function removeModal(id) { 48 | return { 49 | type: REMOVE_MODAL, 50 | payload: id 51 | }; 52 | } 53 | 54 | export function clearAll() { 55 | return { 56 | type: CLEAR_ALL 57 | }; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export function createReducer(initialState, fnMap) { 4 | return (state = initialState, {type, payload}) => { 5 | const handle = fnMap[type]; 6 | return handle ? handle(state, payload) : state; 7 | }; 8 | } 9 | --------------------------------------------------------------------------------