├── .babelrc
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .travis.yml
├── README.md
├── build
└── modal.js
├── example
├── README.md
├── app.js
├── components
│ └── modals
│ │ └── example.jsx
├── dist
│ ├── bundle.js
│ └── index.html
├── package.json
├── styles
│ └── default.scss
├── webpack.config.dev.js
├── webpack.config.production.js
└── webpack.server.js
├── package.json
├── src
└── modal.jsx
├── styles
├── modal.css
└── modal.scss
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "stage": 0
3 | }
4 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | example/webpack.*
2 | example/dist
3 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint-config-airbnb",
3 | "env": {
4 | "browser": true,
5 | "mocha": true,
6 | "node": true
7 | },
8 | "globals": {
9 | "__DEV__": true
10 | },
11 | "rules": {
12 | "valid-jsdoc": 2,
13 | "no-console": 0,
14 | "no-else-return": 0,
15 | "new-cap": 0,
16 | "id-length": [2, { "exceptions": ["e"] }],
17 |
18 | "react/jsx-uses-react": 2,
19 | "react/jsx-uses-vars": 2,
20 | "react/react-in-jsx-scope": 2
21 | },
22 | "plugins": [
23 | "react"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | npm-debug.log
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "4.0.0"
4 | script: npm test
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Modal component for React
2 | [](https://travis-ci.org/fcomb/react-f-ui-modal)
3 |
4 | ### Features
5 | * full control of content
6 | * outer click closes modal
7 | * `esc` closes too!
8 | * stateless: just pass `active` as prop
9 | * animation with [react-motion](https://github.com/chenglou/react-motion)
10 | * overflow scrolls content
11 |
12 | 
13 |
14 | ### Install
15 |
16 | `npm i --save react-f-ui-modal`
17 |
18 | ### Usage
19 | 1. Include component
20 |
21 | import Modal from 'react-f-ui-modal';
22 |
23 | 2. Import SCSS or CSS
24 |
25 | @import "node_modules/react-f-ui-modal/styles/modal"
26 |
27 | 3. Or import directly with webpack's [css-loader](https://github.com/webpack/css-loader)/[sass-loader](https://github.com/jtangelder/sass-loader)
28 |
29 | import 'react-f-ui-modal/styles/modal';
30 |
31 | 4. Make basic modal **(warning: it's stage 0 in babel)**
32 |
33 | import React, { Component, PropTypes } from 'react';
34 | import Modal from 'react-f-ui-modal';
35 |
36 | class ExampleModal extends Component {
37 | static propTypes = {
38 | children: PropTypes.node.isRequired,
39 | handleClose: PropTypes.func,
40 | }
41 |
42 | constructor() {
43 | super();
44 |
45 | this.state = {
46 | isOpen: false,
47 | };
48 | }
49 |
50 | toggleModal() {
51 | this.setState({ isOpen: !this.state.isOpen }, () => {
52 | if (this.props.handleClose) {
53 | this.props.handleClose(this.state);
54 | }
55 | });
56 | }
57 |
58 | render() {
59 | return (
60 |
61 | {this.props.children}
62 |
63 |
64 |
65 |
Modal header
66 | ×
67 |
68 |
69 | Basic modal
70 |
71 |
72 |
73 | );
74 | }
75 | }
76 |
77 | export default ExampleModal;
78 |
79 | 5. And then include with children which toggles modal
80 |
81 | import React from 'react';
82 | import ExampleModal from 'components/modals/example';
83 |
84 | React.render((
85 |
86 | Launch example modal
87 |
88 | ), document.getElementById('app'));
89 |
90 | ### Props
91 | #### active (bool.isRequired)
92 | State of modal.
93 |
94 | #### className (string)
95 | Additional className, default is `f-modal`.
96 |
97 | #### children (node)
98 | Body of modal.
99 |
100 | #### onClose (func.isRequired)
101 | Handler of close modal.
102 |
103 | #### closeOnOuterClick (bool)
104 | Close if click outside content?
105 |
106 | ### Example
107 | * [Demo](http://fcomb.github.io/react-f-ui-modal/)
108 | * [Source code](https://github.com/fcomb/react-f-ui-modal/tree/master/example)
109 |
--------------------------------------------------------------------------------
/build/modal.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, '__esModule', {
4 | value: true
5 | });
6 |
7 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
8 |
9 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
10 |
11 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
12 |
13 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
14 |
15 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
16 |
17 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
18 |
19 | var _react = require('react');
20 |
21 | var _react2 = _interopRequireDefault(_react);
22 |
23 | var _reactMotion = require('react-motion');
24 |
25 | var _classnames = require('classnames');
26 |
27 | var _classnames2 = _interopRequireDefault(_classnames);
28 |
29 | var Modal = (function (_Component) {
30 | _inherits(Modal, _Component);
31 |
32 | _createClass(Modal, null, [{
33 | key: 'propTypes',
34 | value: {
35 | active: _react.PropTypes.bool.isRequired,
36 | closeOnOuterClick: _react.PropTypes.bool,
37 | className: _react.PropTypes.string,
38 | children: _react.PropTypes.node,
39 | onClose: _react.PropTypes.func.isRequired
40 | },
41 | enumerable: true
42 | }]);
43 |
44 | function Modal(props) {
45 | _classCallCheck(this, Modal);
46 |
47 | _get(Object.getPrototypeOf(Modal.prototype), 'constructor', this).call(this, props);
48 |
49 | this.hideOnOuterClick = this.hideOnOuterClick.bind(this);
50 | }
51 |
52 | _createClass(Modal, [{
53 | key: 'componentDidMount',
54 | value: function componentDidMount() {
55 | document.addEventListener('keydown', this.onKeyDown.bind(this), false);
56 | }
57 | }, {
58 | key: 'componentWillUnmount',
59 | value: function componentWillUnmount() {
60 | document.removeEventListener('keydown', this.onKeyDown.bind(this), false);
61 | }
62 | }, {
63 | key: 'onKeyDown',
64 | value: function onKeyDown(e) {
65 | var keyCode = e.keyCode;
66 |
67 | if (this.props.active && keyCode === 27) {
68 | this.props.onClose();
69 | }
70 | }
71 | }, {
72 | key: 'hideOnOuterClick',
73 | value: function hideOnOuterClick(e) {
74 | if (!this.props.closeOnOuterClick) return;
75 | if (e.target.dataset.modal) {
76 | this.props.onClose(e);
77 | }
78 | }
79 | }, {
80 | key: 'render',
81 | value: function render() {
82 | var _this = this;
83 |
84 | if (!this.props.active) {
85 | return null;
86 | }
87 |
88 | var className = {
89 | 'f-modal': true,
90 | 'active': this.props.active
91 | };
92 |
93 | return _react2['default'].createElement(
94 | _reactMotion.Spring,
95 | { defaultValue: { top: { val: -10 }, opacity: { val: 0 } }, endValue: { top: { val: 10 }, opacity: { val: 1 } } },
96 | function (interpolated) {
97 | var top = interpolated.top;
98 | var opacity = interpolated.opacity;
99 |
100 | return _react2['default'].createElement(
101 | 'div',
102 | _extends({}, _this.props, { className: (0, _classnames2['default'])(className, _this.props.className), onClick: _this.hideOnOuterClick, 'data-modal': 'true' }),
103 | _react2['default'].createElement(
104 | 'div',
105 | { className: 'f-modal-content', style: { top: top.val + 'rem', opacity: opacity.val } },
106 | _this.props.children
107 | )
108 | );
109 | }
110 | );
111 | }
112 | }]);
113 |
114 | return Modal;
115 | })(_react.Component);
116 |
117 | exports['default'] = Modal;
118 | module.exports = exports['default'];
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | ```
2 | npm install
3 | npm start
4 | open http://localhost:7000
5 | ```
6 |
--------------------------------------------------------------------------------
/example/app.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ExampleModal from 'components/modals/example';
3 |
4 | import 'styles/default';
5 |
6 | React.render((
7 |
8 |
9 |
12 |
13 | Launch example modal
14 |
15 |
16 |
17 | ), document.getElementById('app'));
18 |
--------------------------------------------------------------------------------
/example/components/modals/example.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component, PropTypes } from 'react';
2 | import Modal from 'react-f-ui-modal';
3 |
4 | // if webpack
5 | import 'react-f-ui-modal/styles/modal';
6 |
7 | class ExampleModal extends Component {
8 | static propTypes = {
9 | children: PropTypes.node.isRequired,
10 | handleClose: PropTypes.func,
11 | }
12 |
13 | constructor() {
14 | super();
15 |
16 | this.state = {
17 | isOpen: false,
18 | };
19 | }
20 |
21 | render() {
22 | return (
23 |
24 | {this.props.children}
25 |
26 |
27 |
28 |
Modal header
29 | ×
30 |
31 |
32 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
33 |
Close modal inside body
34 |
35 |
36 |
37 | );
38 | }
39 |
40 | toggleModal() {
41 | this.setState({ isOpen: !this.state.isOpen }, () => {
42 | if (this.props.handleClose) {
43 | this.props.handleClose(this.state);
44 | }
45 | });
46 | }
47 | }
48 |
49 | export default ExampleModal;
50 |
--------------------------------------------------------------------------------
/example/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-f-ui-modal-example",
3 | "version": "1.0.0",
4 | "main": "webpack.server.js",
5 | "scripts": {
6 | "start": "node webpack.server.js",
7 | "build": "webpack -p"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/fcomb/react-f-ui-modal.git"
12 | },
13 | "license": "MIT",
14 | "bugs": {
15 | "url": "https://github.com/fcomb/react-f-ui-modal/issues"
16 | },
17 | "homepage": "https://github.com/fcomb/react-f-ui-modal",
18 | "dependencies": {
19 | "react": "^0.13.3"
20 | },
21 | "devDependencies": {
22 | "babel-core": "^5.6.18",
23 | "babel-loader": "^5.1.4",
24 | "react-hot-loader": "^1.2.7",
25 | "webpack": "^1.9.11",
26 | "webpack-dev-server": "^1.9.0",
27 | "sass-loader": "^2.0.0",
28 | "style-loader": "^0.12.3",
29 | "css-loader": "^0.15.6"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/example/styles/default.scss:
--------------------------------------------------------------------------------
1 | html,
2 | body,
3 | .app {
4 | height: 100%;
5 | }
6 |
7 | body {
8 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
9 | font-size: 14px;
10 | background-color: #fff;
11 | color: #333333;
12 | line-height: 1.42857;
13 | }
14 |
15 | .text-center {
16 | text-align: center;
17 | }
18 |
19 | h3 {
20 | font-weight: 400;
21 | }
22 |
23 | .header-title {
24 | font-family: inherit;
25 | font-size: 3rem;
26 | font-weight: 200;
27 |
28 | &-link {
29 | color: #1E88E5;
30 | border-bottom: 1px solid #90CAF9;
31 | text-decoration: none;
32 | transition: color, border-bottom-color .3s;
33 |
34 | &:hover,
35 | &:visited {
36 | color: #3F51B5;
37 | border-bottom-color: #9FA8DA;
38 | }
39 | }
40 | }
41 |
42 | .container {
43 | display: flex;
44 | justify-content: center;
45 | align-items: center;
46 | height: 100%;
47 |
48 | &-modal {
49 | display: block;
50 | }
51 | }
52 |
53 | .button-cta {
54 | font-family: inherit;
55 | font-size: 2rem;
56 | font-weight: 200;
57 | background: #E91E63;
58 | color: #fff;
59 | padding: 2rem;
60 | border: 1px solid #E91E63;
61 | line-height: 1;
62 |
63 | &:hover {
64 | cursor: poiner;
65 | }
66 |
67 | &:active,
68 | &:focus {
69 | outline: 0;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/example/webpack.config.dev.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 |
4 | module.exports = {
5 | devtool: 'cheap-module-eval-source-map',
6 | entry: [
7 | 'webpack-dev-server/client?http://localhost:7000',
8 | 'webpack/hot/only-dev-server',
9 | './app'
10 | ],
11 | output: {
12 | path: path.join(__dirname, 'dist'),
13 | filename: 'bundle.js'
14 | },
15 | plugins: [
16 | new webpack.HotModuleReplacementPlugin(),
17 | new webpack.NoErrorsPlugin()
18 | ],
19 | resolve: {
20 | alias: {
21 | 'react-f-ui-modal': path.join(__dirname, '..'),
22 | 'components': path.join(__dirname, 'components'),
23 | 'styles': path.join(__dirname, 'styles')
24 | },
25 | extensions: ['', '.js', '.jsx', '.scss']
26 | },
27 | module: {
28 | loaders: [{
29 | test: /(.js|.jsx)/,
30 | loaders: ['react-hot', 'babel'],
31 | exclude: /node_modules/,
32 | include: __dirname
33 | }, {
34 | test: /(.js|.jsx)/,
35 | loaders: ['babel'],
36 | include: path.join(__dirname, '..', 'src')
37 | }, {
38 | test: /\.scss$/,
39 | loader: 'style!css!sass',
40 | include: [
41 | path.join(__dirname, '..', 'styles'),
42 | path.join(__dirname, 'styles')
43 | ]
44 | }]
45 | }
46 | };
47 |
--------------------------------------------------------------------------------
/example/webpack.config.production.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 |
4 | module.exports = {
5 | entry: [
6 | './example/app'
7 | ],
8 | output: {
9 | path: path.join(__dirname, 'dist'),
10 | filename: 'bundle.js',
11 | publicPath: '/dist/'
12 | },
13 | plugins: [
14 | new webpack.NoErrorsPlugin()
15 | ],
16 | resolve: {
17 | alias: {
18 | 'react-f-ui-modal': path.join(__dirname, '..'),
19 | 'components': path.join(__dirname, 'components'),
20 | 'styles': path.join(__dirname, 'styles')
21 | },
22 | extensions: ['', '.js', '.jsx', '.scss']
23 | },
24 | module: {
25 | loaders: [{
26 | test: /(.js|.jsx)/,
27 | loaders: ['babel'],
28 | include: [
29 | __dirname,
30 | path.join(__dirname, '..', 'src')
31 | ]
32 | }, {
33 | test: /\.scss$/,
34 | loader: 'style!css!sass',
35 | include: [
36 | path.join(__dirname, '..', 'styles'),
37 | path.join(__dirname, 'styles')
38 | ]
39 | }]
40 | }
41 | };
42 |
--------------------------------------------------------------------------------
/example/webpack.server.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require('path');
3 | var WebpackDevServer = require('webpack-dev-server');
4 | var config = require('./webpack.config.dev');
5 |
6 | new WebpackDevServer(webpack(config), {
7 | publicPath: config.output.publicPath,
8 | contentBase: path.join(__dirname, 'dist'),
9 | hot: true,
10 | historyApiFallback: true,
11 | stats: {
12 | colors: true,
13 | }
14 | }).listen(7000, 'localhost', function (err) {
15 | if (err) {
16 | console.log(err);
17 | }
18 |
19 | console.log('Listening at localhost:7000');
20 | });
21 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-f-ui-modal",
3 | "version": "2.0.1",
4 | "description": "Modal component for React",
5 | "main": "build/modal.js",
6 | "scripts": {
7 | "test": "npm run lint",
8 | "clean": "$(npm bin)/rimraf build",
9 | "lint": "$(npm bin)/eslint --ext .jsx --ext .js src",
10 | "build:jsx": "$(npm bin)/babel src --out-dir build",
11 | "build:scss": "$(npm bin)/node-sass styles/modal.scss styles/modal.css",
12 | "build:example": "$(npm bin)/webpack -p --config example/webpack.config.production.js",
13 | "build": "npm run build:jsx && npm run build:scss",
14 | "prepublish": "npm run clean && npm run test && npm run build",
15 | "deploy:git-push": "git push origin master",
16 | "deploy:ghpages": "$(npm bin)/gh-pages -d example/dist",
17 | "deploy": "npm run build:example && git add -A && git commit -am 'chore: update docs' && npm run deploy:git-push && npm run deploy:ghpages"
18 | },
19 | "repository": {
20 | "type": "git",
21 | "url": "git+https://github.com/fcomb/react-f-ui-modal.git"
22 | },
23 | "keywords": [
24 | "react",
25 | "modal",
26 | "react-modal",
27 | "react-component"
28 | ],
29 | "author": "Eugene Rodionov (https://github.com/theaqua)",
30 | "license": "MIT",
31 | "bugs": {
32 | "url": "https://github.com/fcomb/react-f-ui-modal/issues"
33 | },
34 | "homepage": "https://github.com/fcomb/react-f-ui-modal#readme",
35 | "dependencies": {
36 | "classnames": "2.2.0",
37 | "react-motion": "0.2.7"
38 | },
39 | "peerDependencies": {
40 | "react": "^0.14.2"
41 | },
42 | "devDependencies": {
43 | "babel": "5.8.29",
44 | "babel-eslint": "4.1.3",
45 | "babel-loader": "5.3.3",
46 | "eslint": "1.7.3",
47 | "eslint-config-airbnb": "0.1.0",
48 | "eslint-plugin-react": "3.6.3",
49 | "gh-pages": "0.5.0",
50 | "node-sass": "3.4.1",
51 | "rimraf": "2.4.3",
52 | "webpack": "1.12.2"
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/modal.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component, PropTypes } from 'react';
2 | import { Spring } from 'react-motion';
3 | import cn from 'classnames';
4 |
5 | class Modal extends Component {
6 | static propTypes = {
7 | active: PropTypes.bool.isRequired,
8 | closeOnOuterClick: PropTypes.bool,
9 | className: PropTypes.string,
10 | children: PropTypes.node,
11 | onClose: PropTypes.func.isRequired,
12 | }
13 |
14 | constructor(props) {
15 | super(props);
16 |
17 | this.hideOnOuterClick = ::this.hideOnOuterClick;
18 | }
19 |
20 | componentDidMount() {
21 | document.addEventListener('keydown', ::this.onKeyDown, false);
22 | }
23 |
24 | componentWillUnmount() {
25 | document.removeEventListener('keydown', ::this.onKeyDown, false);
26 | }
27 |
28 | onKeyDown(e) {
29 | const { keyCode } = e;
30 |
31 | if (this.props.active && keyCode === 27) {
32 | this.props.onClose();
33 | }
34 | }
35 |
36 | hideOnOuterClick(e) {
37 | if (!this.props.closeOnOuterClick) return;
38 | if (e.target.dataset.modal) {
39 | this.props.onClose(e);
40 | }
41 | }
42 |
43 | render() {
44 | if (!this.props.active) {
45 | return null;
46 | }
47 |
48 | const className = {
49 | 'f-modal': true,
50 | 'active': this.props.active,
51 | };
52 |
53 | return (
54 |
55 | {interpolated => {
56 | const { top, opacity } = interpolated;
57 |
58 | return (
59 |
60 |
61 | {this.props.children}
62 |
63 |
64 | );
65 | }}
66 |
67 | );
68 | }
69 | }
70 |
71 | export default Modal;
72 |
--------------------------------------------------------------------------------
/styles/modal.css:
--------------------------------------------------------------------------------
1 | .f-modal {
2 | display: none;
3 | position: fixed;
4 | top: 0;
5 | bottom: 0;
6 | left: 0;
7 | right: 0;
8 | background: rgba(0, 0, 0, 0.8);
9 | z-index: 1040;
10 | pointer-events: auto;
11 | overflow: scroll; }
12 | .f-modal-content {
13 | position: relative;
14 | background: #fff;
15 | margin: 0 auto 1rem;
16 | opacity: 0;
17 | width: 600px; }
18 | .f-modal_sm .f-modal-content {
19 | width: 300px; }
20 | .f-modal_md .f-modal-content {
21 | width: 600px; }
22 | .f-modal_lg .f-modal-content {
23 | width: 900px; }
24 | .f-modal.active {
25 | display: block; }
26 | .f-modal-close {
27 | position: absolute;
28 | top: -4rem;
29 | right: -4rem;
30 | font-size: 3rem;
31 | background-color: transparent;
32 | color: #fff;
33 | border: 0;
34 | line-height: 1;
35 | transition: color .3s; }
36 | .f-modal-close:hover {
37 | color: #848484; }
38 | .f-modal-close:active, .f-modal-close:focus {
39 | outline: 0; }
40 | .f-modal-header {
41 | padding: 1.5rem 2rem;
42 | border-bottom: 1px solid #eee; }
43 | .f-modal-header-title {
44 | margin: 0; }
45 | .f-modal-body {
46 | padding: 1rem 2rem; }
47 |
--------------------------------------------------------------------------------
/styles/modal.scss:
--------------------------------------------------------------------------------
1 | $f-modal-zIndex: 1040;
2 | $f-modal-size-lg: 900px;
3 | $f-modal-size-md: 600px;
4 | $f-modal-size-sm: 300px;
5 |
6 | @mixin modalSize($size) {
7 | .f-modal-content {
8 | width: $size;
9 | }
10 | }
11 |
12 | .f-modal {
13 | display: none;
14 | position: fixed;
15 | top: 0;
16 | bottom: 0;
17 | left: 0;
18 | right: 0;
19 | background: rgba(0, 0, 0, 0.8);
20 | z-index: $f-modal-zIndex;
21 | pointer-events: auto;
22 | overflow: scroll;
23 |
24 | &-content {
25 | position: relative;
26 | background: #fff;
27 | margin: 0 auto 1rem;
28 | opacity: 0;
29 | width: $f-modal-size-md;
30 | }
31 |
32 | &_sm {
33 | @include modalSize($f-modal-size-sm);
34 | }
35 |
36 | &_md {
37 | @include modalSize($f-modal-size-md);
38 | }
39 |
40 | &_lg {
41 | @include modalSize($f-modal-size-lg);
42 | }
43 |
44 | &.active {
45 | display: block;
46 | }
47 |
48 | &-close {
49 | position: absolute;
50 | top: -4rem;
51 | right: -4rem;
52 | font-size: 3rem;
53 | background-color: transparent;
54 | color: #fff;
55 | border: 0;
56 | line-height: 1;
57 | transition: color .3s;
58 |
59 | &:hover {
60 | color: #848484;
61 | }
62 |
63 | &:active,
64 | &:focus {
65 | outline: 0;
66 | }
67 | }
68 |
69 | &-header {
70 | padding: 1.5rem 2rem;
71 | border-bottom: 1px solid #eee;
72 |
73 | &-title {
74 | margin: 0;
75 | }
76 | }
77 |
78 | &-body {
79 | padding: 1rem 2rem;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 |
4 | const config = {
5 | entry: [
6 | // 'webpack-dev-server/client?http://0.0.0.0:3000',
7 | // 'webpack/hot/only-dev-server',
8 | './src/modal',
9 | './src/styles/modal',
10 | ],
11 | output: {
12 | path: path.join(__dirname, '/build'),
13 | filename: 'modal.js',
14 | },
15 | module: {
16 | noParse: ['node_modules/react'],
17 | loaders: [
18 | { test: /(.js|.jsx)/, exclude: /node_modules/, loader: 'babel?cacheDirectory=true' },
19 | { test: /\.scss$/, loader: 'style!css!sass' },
20 | ],
21 | },
22 | resolve: {
23 | root: path.join(__dirname, '/src'),
24 | extensions: ['', '.js', '.json', '.jsx', '.scss'],
25 | },
26 | plugins: [
27 | new webpack.HotModuleReplacementPlugin(),
28 | new webpack.NoErrorsPlugin(),
29 | new webpack.optimize.DedupePlugin(),
30 | ],
31 | devtool: 'cheap-module-eval-source-map',
32 | };
33 |
34 | module.exports = config;
35 |
--------------------------------------------------------------------------------