Skip to content

Commit

Permalink
fix: merge with upstream
Browse files Browse the repository at this point in the history
  • Loading branch information
Eugene Rodionov committed Feb 2, 2016
2 parents 96044a3 + b313e70 commit 9d594d8
Show file tree
Hide file tree
Showing 12 changed files with 100 additions and 45 deletions.
1 change: 1 addition & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"presets": ["react", "es2015"],
"plugins": ["add-module-exports"],
"env": {
"development": {
"presets": ["react-hmre"]
Expand Down
1 change: 0 additions & 1 deletion .eslintignore

This file was deleted.

3 changes: 0 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ node_js:
- "5"
- "4.1"
- "4.0"
before_script:
- npm install react react-dom
script:
- npm run lint
- npm test
- npm run build
- npm run build:examples
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2015 Vojtech Miksu
Copyright (c) 2016 Vojtech Miksu

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
26 changes: 10 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ Try [http://miksu.cz/react-portal](http://miksu.cz/react-portal) **or**
git clone https://github.com/tajo/react-portal
cd react-portal
npm install
npm install react react-dom
npm run build:examples
open examples/index.html
```
Expand All @@ -39,7 +38,7 @@ npm install react react-dom react-portal --save
```

## Usage
```javascript
```jsx
import React from 'react';
import ReactDOM from 'react-dom';
import Portal from 'react-portal';
Expand Down Expand Up @@ -117,7 +116,7 @@ This callback is called when the portal is (re)rendered.
- Does your modal have a fullscreen overlay and the `closeOnOutsideClick` doesn't work? [There is a simple solution](https://github.com/tajo/react-portal/issues/2#issuecomment-92058826).
- Does your inner inner component `<LevelTwo />`

```js
```jsx
<Portal>
<LevelOne>
<LevelTwo />
Expand All @@ -127,35 +126,32 @@ This callback is called when the portal is (re)rendered.

also needs an access to `this.props.closePortal()`? You can't just use `{this.props.children}` in render method of `<LevelOne>` component. You have to clone it instead:

```js
```jsx
{React.cloneElement(
this.props.children,
{closePortal: this.props.closePortal}
)}
```

#### Don't read this
Please, skip this section if you dislike dirty tricks.
#### Open modal programmatically

**States make everything harder, right?** We don't want to deal with them, right? But sometime you need to open a portal (e.g. modal) automatically. There is no button to click on. No problem, because the portal has the `isOpen` prop, so you can just set it `true` or `false`.
Sometimes you need to open your portal (e.g. modal) automatically. There is no button to click on. No problem, because the portal has the `isOpen` prop, so you can just set it to `true` or `false`. However, then it's completely up to you to take care about the portal closing (ESC, outside click, no `this.props.closePortal` callback...).

However, then it's completely up to you to take care about the open state. You have to write all the closing logic! And that sucks. But there is a dirty trick:
However, there is a nice trick how to make this happen even without `isOpen`:

```javascript
<Portal openByClickOn={<span ref="myLittleSecret" />}>
```jsx
<Portal ref="myPortal">
<Modal title="My modal">
Modal content
</Modal>
</Portal>
```

```javascript
ReactDOM.findDOMNode(this.refs.myLittleSecret).click();
```jsx
this.refs.myPortal.openPortal()
// opens the portal, yay!
```

I'll end up in hell. I know.

## Contribution

Please, create issues and pull requests.
Expand All @@ -164,15 +160,13 @@ Please, create issues and pull requests.
git clone https://github.com/tajo/react-portal
cd react-portal
npm install
npm install react react-dom
npm start
open http://localhost:3000
```

**Don't forget to run this before every commit:**

```
npm run lint
npm test
```

Expand Down
4 changes: 2 additions & 2 deletions examples/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default class App extends React.Component {
new TWEEN.Tween({opacity: 0})
.to({opacity: 1}, 500)
.easing(TWEEN.Easing.Cubic.In)
.onUpdate(() => {
.onUpdate(function() {
node.style.opacity = this.opacity;
}).start();
}
Expand All @@ -35,7 +35,7 @@ export default class App extends React.Component {
new TWEEN.Tween({opacity: 1})
.to({opacity: 0}, 500)
.easing(TWEEN.Easing.Cubic.In)
.onUpdate(() => {
.onUpdate(function() {
node.style.opacity = this.opacity;
})
.onComplete(removeFromDom)
Expand Down
32 changes: 18 additions & 14 deletions lib/portal.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default class Portal extends React.Component {
constructor() {
super();
this.state = {active: false};
this.openPortal = this.openPortal.bind(this);
this.handleWrapperClick = this.handleWrapperClick.bind(this);
this.closePortal = this.closePortal.bind(this);
this.handleOutsideMouseClick = this.handleOutsideMouseClick.bind(this);
this.handleKeydown = this.handleKeydown.bind(this);
Expand All @@ -31,7 +31,7 @@ export default class Portal extends React.Component {
}

if (this.props.isOpened) {
this.openPortal(this.props);
this.openPortal();
}
}

Expand Down Expand Up @@ -89,17 +89,19 @@ export default class Portal extends React.Component {

render() {
if (this.props.openByClickOn) {
return React.cloneElement(this.props.openByClickOn, {onClick: this.openPortal.bind(this, this.props)});
return React.cloneElement(this.props.openByClickOn, {onClick: this.handleWrapperClick});
} else {
return null;
}
}

openPortal(props, e) {
if (e) {
e.preventDefault();
e.stopPropagation();
}
handleWrapperClick(e) {
e.preventDefault();
e.stopPropagation();
this.openPortal();
}

openPortal(props = this.props) {
this.setState({active: true});
this.renderPortal(props);

Expand All @@ -117,13 +119,15 @@ export default class Portal extends React.Component {
this.setState({active: false});
};

if (this.props.beforeClose) {
this.props.beforeClose(this.node, resetPortalState);
} else {
resetPortalState(this.node);
}
if (this.state.active) {
if (this.props.beforeClose) {
this.props.beforeClose(this.node, resetPortalState);
} else {
resetPortalState();
}

this.props.onClose();
this.props.onClose();
}
}

handleOutsideMouseClick(e) {
Expand Down
27 changes: 20 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
{
"name": "react-portal",
"version": "1.7.0",
"description": "React component for transportation of modals, lightboxes, loading bars... to document.body",
"main": "build/portal",
"description": "Simple React component for transportation of your modals, lightboxes, etc. to document.body",
"author": "Vojtech Miksu <[email protected]>",
"version": "1.5.1",
"license": "MIT",
"files": [
"*.md",
"LICENSE",
"lib",
"build"
],
"repository": {
"type": "git",
"url": "https://github.com/tajo/react-portal"
},
"author": "Vojtech Miksu <[email protected]>",
"license": "MIT",
"scripts": {
"start": "node devServer.js",
"build": "mkdir -p build && babel ./lib/portal.js --out-file ./build/portal.js",
"build:examples": "npm run clean && npm run build:examples:webpack",
"build:examples:webpack": "cross-env NODE_ENV=production webpack --config webpack.config.prod.js",
"clean": "rimraf build",
"test": "NODE_ENV=test mocha --compilers js:babel-register",
"lint": "eslint examples lib test",
"prepublish": "npm run build"
"test": "mocha",
"lint": "mocha test/eslint_spec.js",
"prepublish": "cross-env NODE_ENV=production npm run build"
},
"tags": [
"react"
],
"keywords": [
"react",
"react-component",
Expand All @@ -37,6 +46,7 @@
"babel-core": "^6.4.0",
"babel-eslint": "^4.1.6",
"babel-loader": "^6.2.1",
"babel-plugin-add-module-exports": "^0.1.2",
"babel-preset-es2015": "^6.3.13",
"babel-preset-react": "^6.3.13",
"babel-preset-react-hmre": "^1.0.1",
Expand All @@ -48,7 +58,10 @@
"express": "^4.13.3",
"jsdom": "^7.2.2",
"mocha": "^2.3.4",
"mocha-eslint": "^1.0.0",
"react": "^0.14.7",
"react-addons-test-utils": "^0.14.6",
"react-dom": "^0.14.7",
"rimraf": "^2.5.0",
"sinon": "^1.17.2",
"tween.js": "^16.3.1",
Expand Down
1 change: 1 addition & 0 deletions test/eslint_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require('mocha-eslint')('examples lib test devServer.js'.split(' '));
1 change: 1 addition & 0 deletions test/mocha.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
process.env.NODE_ENV = 'test';
2 changes: 2 additions & 0 deletions test/mocha.opts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--compilers js:babel-register
--require ./test/mocha.js
45 changes: 44 additions & 1 deletion test/portal_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import jsdom from 'jsdom';
import Portal from '../lib/portal';
import assert from 'assert';
import {spy} from 'sinon';
import {render, unmountComponentAtNode} from 'react-dom';
import {
mount,
spyLifecycle
Expand Down Expand Up @@ -36,6 +37,13 @@ describe('react-portal', () => {
assert.equal(document.body.childElementCount, 1);
});

it('should open when this.openPortal() is called (used to programmatically open portal)', () => {
const wrapper = mount(<Portal><p>Hi</p></Portal>);
assert.equal(document.body.childElementCount, 0);
wrapper.instance().openPortal();
assert.equal(wrapper.instance().node.firstElementChild.tagName, 'P');
});

it('when props.isOpened is false and then set to true should open portal', () => {
const wrapper = mount(<Portal isOpened={false}><p>Hi</p></Portal>);
assert.equal(document.body.childElementCount, 0);
Expand Down Expand Up @@ -81,12 +89,22 @@ describe('react-portal', () => {
const props = {isOpened: true, beforeClose: spy()};
const wrapper = mount(<Portal {...props}><p>Hi</p></Portal>);
wrapper.instance().closePortal();
assert(props.beforeClose.calledOnce);
assert(props.beforeClose.calledWith(wrapper.instance().node));
});

it('should call props.beforeClose() only once even if closePortal is called multiple times', () => {
const props = {isOpened: true, beforeClose: spy((node, cb) => cb())};
const wrapper = mount(<Portal {...props}><p>Hi</p></Portal>);
wrapper.instance().closePortal();
wrapper.instance().closePortal();
assert(props.beforeClose.calledOnce);
});

it('should call props.onOpen() when portal opens', () => {
const props = {isOpened: true, onOpen: spy()};
const wrapper = mount(<Portal {...props}><p>Hi</p></Portal>);
assert(props.onOpen.calledOnce);
assert(props.onOpen.calledWith(wrapper.instance().node));
});

Expand All @@ -110,7 +128,32 @@ describe('react-portal', () => {
const props = {isOpened: true, onClose: spy()};
const wrapper = mount(<Portal {...props}><p>Hi</p></Portal>);
wrapper.instance().closePortal();
assert(props.onClose.called);
assert(props.onClose.calledOnce);
});

it('should call props.onClose() only once even if closePortal is called multiple times', () => {
const props = {isOpened: true, onClose: spy()};
const wrapper = mount(<Portal {...props}><p>Hi</p></Portal>);
wrapper.instance().closePortal();
wrapper.instance().closePortal();
assert(props.onClose.calledOnce);
});

it('should call props.onClose() only once when portal closes and then is unmounted', () => {
const div = document.createElement('div');
const props = {isOpened: true, onClose: spy()};
const component = render(<Portal {...props}><p>Hi</p></Portal>, div);
component.closePortal();
unmountComponentAtNode(div);
assert(props.onClose.calledOnce);
});

it('should call props.onClose() only once when directly unmounting', () => {
const div = document.createElement('div');
const props = {isOpened: true, onClose: spy()};
render(<Portal {...props}><p>Hi</p></Portal>, div);
unmountComponentAtNode(div);
assert(props.onClose.calledOnce);
});
});

Expand Down

0 comments on commit 9d594d8

Please sign in to comment.