diff --git a/lib/base-components.js b/lib/base-components.js
new file mode 100644
index 00000000..7b7af94d
--- /dev/null
+++ b/lib/base-components.js
@@ -0,0 +1,69 @@
+import React from 'react';
+import {StyleSheet, css} from 'aphrodite-simple';
+
+const decorateBaseComponent = Component => {
+ return class BaseComponent extends Component {
+ constructor() {
+ super();
+ this.styles_ = this.createStyleSheet();
+ this.cssHelper = this.cssHelper.bind(this);
+ }
+
+ createStyleSheet() {
+ if (!this.styles) {
+ return {};
+ }
+
+ const styles = this.styles();
+
+ if (typeof styles !== 'object') {
+ throw new TypeError('Component `styles` returns a non-object');
+ }
+
+ return StyleSheet.create(this.styles());
+ }
+
+ // wrap aphrodite's css helper for two reasons:
+ // - we can give the element an unaltered global classname
+ // that can be used to introduce global css side effects
+ // for example, through the configuration, web inspector
+ // or user agent extensions
+ // - the user doesn't need to keep track of both `css`
+ // and `style`, and we make that whole ordeal easier
+ cssHelper(...args) {
+ const classes = args
+ .map(c => {
+ if (c) {
+ // we compute the global name from the given
+ // css class and we prepend the component name
+ //
+ // it's important classes never get mangled by
+ // uglifiers so that we can avoid collisions
+ const component = this.constructor.name.toString().toLowerCase();
+ const globalName = `${component}_${c}`;
+ return [globalName, css(this.styles_[c])];
+ }
+ return null;
+ })
+ // skip nulls
+ .filter(v => Boolean(v))
+ // flatten
+ .reduce((a, b) => a.concat(b));
+ return classes.length ? classes.join(' ') : null;
+ }
+
+ render() {
+ // convert static objects from `babel-plugin-transform-jsx`
+ // to `React.Element`.
+ if (!this.template) {
+ throw new TypeError("Component doesn't define `template`");
+ }
+
+ // invoke the template creator passing our css helper
+ return this.template(this.cssHelper);
+ }
+ };
+};
+
+export const PureComponent = decorateBaseComponent(React.PureComponent);
+export const Component = decorateBaseComponent(React.Component);
diff --git a/lib/component.js b/lib/component.js
deleted file mode 100644
index e5a98990..00000000
--- a/lib/component.js
+++ /dev/null
@@ -1,64 +0,0 @@
-import React from 'react';
-import {StyleSheet, css} from 'aphrodite-simple';
-
-export default class Component extends React.PureComponent {
- constructor() {
- super();
- this.styles_ = this.createStyleSheet();
- this.cssHelper = this.cssHelper.bind(this);
- }
-
- createStyleSheet() {
- if (!this.styles) {
- return {};
- }
-
- const styles = this.styles();
-
- if (typeof styles !== 'object') {
- throw new TypeError('Component `styles` returns a non-object');
- }
-
- return StyleSheet.create(this.styles());
- }
-
- // wrap aphrodite's css helper for two reasons:
- // - we can give the element an unaltered global classname
- // that can be used to introduce global css side effects
- // for example, through the configuration, web inspector
- // or user agent extensions
- // - the user doesn't need to keep track of both `css`
- // and `style`, and we make that whole ordeal easier
- cssHelper(...args) {
- const classes = args
- .map(c => {
- if (c) {
- // we compute the global name from the given
- // css class and we prepend the component name
- //
- // it's important classes never get mangled by
- // uglifiers so that we can avoid collisions
- const component = this.constructor.name.toString().toLowerCase();
- const globalName = `${component}_${c}`;
- return [globalName, css(this.styles_[c])];
- }
- return null;
- })
- // skip nulls
- .filter(v => Boolean(v))
- // flatten
- .reduce((a, b) => a.concat(b));
- return classes.length ? classes.join(' ') : null;
- }
-
- render() {
- // convert static objects from `babel-plugin-transform-jsx`
- // to `React.Element`.
- if (!this.template) {
- throw new TypeError("Component doesn't define `template`");
- }
-
- // invoke the template creator passing our css helper
- return this.template(this.cssHelper);
- }
-}
diff --git a/lib/components/header.js b/lib/components/header.js
index c7d4b347..b1a618b1 100644
--- a/lib/components/header.js
+++ b/lib/components/header.js
@@ -1,13 +1,13 @@
import React from 'react';
-import Component from '../component';
+import {PureComponent} from '../base-components';
import {decorate, getTabsProps} from '../utils/plugins';
import Tabs_ from './tabs';
const Tabs = decorate(Tabs_, 'Tabs');
-export default class Header extends Component {
+export default class Header extends PureComponent {
constructor() {
super();
this.onChangeIntent = this.onChangeIntent.bind(this);
diff --git a/lib/components/notification.js b/lib/components/notification.js
index d28af573..bb2c421e 100644
--- a/lib/components/notification.js
+++ b/lib/components/notification.js
@@ -1,7 +1,7 @@
import React from 'react';
-import Component from '../component';
+import {PureComponent} from '../base-components';
-export default class Notification extends Component {
+export default class Notification extends PureComponent {
constructor() {
super();
this.state = {
diff --git a/lib/components/notifications.js b/lib/components/notifications.js
index d6e0bf70..a70dc77a 100644
--- a/lib/components/notifications.js
+++ b/lib/components/notifications.js
@@ -1,13 +1,13 @@
import React from 'react';
-import Component from '../component';
+import {PureComponent} from '../base-components';
import {decorate} from '../utils/plugins';
import Notification_ from './notification';
const Notification = decorate(Notification_);
-export default class Notifications extends Component {
+export default class Notifications extends PureComponent {
template(css) {
return (
diff --git a/lib/components/split-pane.js b/lib/components/split-pane.js
index 031fc681..7b0016c1 100644
--- a/lib/components/split-pane.js
+++ b/lib/components/split-pane.js
@@ -1,8 +1,8 @@
/* eslint-disable quote-props */
import React from 'react';
-import Component from '../component';
+import {PureComponent} from '../base-components';
-export default class SplitPane extends Component {
+export default class SplitPane extends PureComponent {
constructor(props) {
super(props);
this.handleDragStart = this.handleDragStart.bind(this);
diff --git a/lib/components/tab.js b/lib/components/tab.js
index ee204331..1f2a871d 100644
--- a/lib/components/tab.js
+++ b/lib/components/tab.js
@@ -1,7 +1,7 @@
import React from 'react';
-import Component from '../component';
+import {PureComponent} from '../base-components';
-export default class Tab extends Component {
+export default class Tab extends PureComponent {
constructor() {
super();
diff --git a/lib/components/tabs.js b/lib/components/tabs.js
index 91e2ef59..38485ca1 100644
--- a/lib/components/tabs.js
+++ b/lib/components/tabs.js
@@ -1,6 +1,6 @@
import React from 'react';
-import Component from '../component';
+import {PureComponent} from '../base-components';
import {decorate, getTabProps} from '../utils/plugins';
import Tab_ from './tab';
@@ -8,7 +8,7 @@ import Tab_ from './tab';
const Tab = decorate(Tab_, 'Tab');
const isMac = /Mac/.test(navigator.userAgent);
-export default class Tabs extends Component {
+export default class Tabs extends PureComponent {
template(css) {
const {tabs = [], borderColor, onChange, onClose} = this.props;
diff --git a/lib/components/term-group.js b/lib/components/term-group.js
index d9a67318..69f7d1d6 100644
--- a/lib/components/term-group.js
+++ b/lib/components/term-group.js
@@ -1,6 +1,6 @@
import React from 'react';
import {connect} from 'react-redux';
-import Component from '../component';
+import {PureComponent} from '../base-components';
import {decorate, getTermProps, getTermGroupProps} from '../utils/plugins';
import {resizeTermGroup} from '../actions/term-groups';
import Term_ from './term';
@@ -9,7 +9,7 @@ import SplitPane_ from './split-pane';
const Term = decorate(Term_, 'Term');
const SplitPane = decorate(SplitPane_, 'SplitPane');
-class TermGroup_ extends Component {
+class TermGroup_ extends PureComponent {
constructor(props, context) {
super(props, context);
this.bound = new WeakMap();
diff --git a/lib/components/term.js b/lib/components/term.js
index 3fabf9d9..f8c6900c 100644
--- a/lib/components/term.js
+++ b/lib/components/term.js
@@ -1,7 +1,7 @@
/* global Blob,URL,requestAnimationFrame */
import React from 'react';
import Terminal from 'xterm';
-import Component from '../component';
+import {PureComponent} from '../base-components';
import terms from '../terms';
import returnKey from '../utils/keymaps';
import CommandRegistry from '../command-registry';
@@ -13,7 +13,7 @@ const CURSOR_STYLES = {
BLOCK: 'block'
};
-export default class Term extends Component {
+export default class Term extends PureComponent {
constructor(props) {
super(props);
props.ref_(props.uid, this);
diff --git a/lib/components/terms.js b/lib/components/terms.js
index ffd55017..97cc562a 100644
--- a/lib/components/terms.js
+++ b/lib/components/terms.js
@@ -1,5 +1,5 @@
import React from 'react';
-import Component from '../component';
+import {Component} from '../base-components';
import {decorate, getTermGroupProps} from '../utils/plugins';
import CommandRegistry from '../command-registry';
import TermGroup_ from './term-group';
diff --git a/lib/containers/hyper.js b/lib/containers/hyper.js
index 4a9ca610..46dc2539 100644
--- a/lib/containers/hyper.js
+++ b/lib/containers/hyper.js
@@ -2,7 +2,7 @@
import React from 'react';
-import Component from '../component';
+import {PureComponent} from '../base-components';
import {connect} from '../utils/plugins';
import * as uiActions from '../actions/ui';
@@ -12,7 +12,7 @@ import NotificationsContainer from './notifications';
const isMac = /Mac/.test(navigator.userAgent);
-class Hyper extends Component {
+class Hyper extends PureComponent {
constructor(props) {
super(props);
this.handleFocusActive = this.handleFocusActive.bind(this);
diff --git a/lib/utils/plugins.js b/lib/utils/plugins.js
index a86555ad..b7bcf36a 100644
--- a/lib/utils/plugins.js
+++ b/lib/utils/plugins.js
@@ -6,7 +6,7 @@ import {connect as reduxConnect} from 'react-redux';
// https://github.com/zeit/hyper/issues/619
import React from 'react';
import ReactDOM from 'react-dom';
-import Component from '../component';
+import {PureComponent} from '../base-components';
import Notification from '../components/notification';
import notify from './notify';
@@ -20,7 +20,7 @@ Module._load = function _load(path) {
case 'react-dom':
return ReactDOM;
case 'hyper/component':
- return Component;
+ return PureComponent;
case 'hyper/notify':
return notify;
case 'hyper/Notification':
@@ -457,7 +457,7 @@ function getDecorated(parent, name) {
let class__;
try {
- class__ = fn(class_, {React, Component, Notification, notify});
+ class__ = fn(class_, {React, PureComponent, Notification, notify});
class__.displayName = `${fn._pluginName}(${name})`;
} catch (err) {
//eslint-disable-next-line no-console
diff --git a/package.json b/package.json
index 2ce6fc4c..7f2c4b40 100644
--- a/package.json
+++ b/package.json
@@ -150,9 +150,9 @@
"mousetrap": "1.6.1",
"ms": "2.0.0",
"php-escape-shell": "1.0.0",
- "react": "15.6.1",
+ "react": "16.0.0-rc.3",
"react-deep-force-update": "2.0.1",
- "react-dom": "15.6.1",
+ "react-dom": "16.0.0-rc.3",
"react-redux": "5.0.6",
"redux": "3.7.2",
"redux-thunk": "2.2.0",
diff --git a/yarn.lock b/yarn.lock
index 5ccb9288..108a4d45 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1725,14 +1725,6 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
-create-react-class@^15.6.0:
- version "15.6.0"
- resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.0.tgz#ab448497c26566e1e29413e883207d57cfe7bed4"
- dependencies:
- fbjs "^0.8.9"
- loose-envify "^1.3.1"
- object-assign "^4.1.1"
-
cross-env@5.0.5:
version "5.0.5"
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.0.5.tgz#4383d364d9660873dd185b398af3bfef5efffef3"
@@ -4178,7 +4170,7 @@ oauth-sign@~0.8.1:
version "0.8.2"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
-object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
+object-assign@^4.0.1, object-assign@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@@ -4814,7 +4806,7 @@ promise@^7.1.1:
dependencies:
asap "~2.0.3"
-prop-types@^15.5.10:
+prop-types@^15.5.10, prop-types@^15.5.6:
version "15.5.10"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
dependencies:
@@ -4896,14 +4888,14 @@ react-deep-force-update@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-2.0.1.tgz#4f7f6c12c3e7de42f345992a3c518236fa1ecad3"
-react-dom@15.6.1:
- version "15.6.1"
- resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.6.1.tgz#2cb0ed4191038e53c209eb3a79a23e2a4cf99470"
+react-dom@16.0.0-rc.3:
+ version "16.0.0-rc.3"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.0.0-rc.3.tgz#bd4e4d2abd464df5149a062b45fe796bbb804c2c"
dependencies:
fbjs "^0.8.9"
loose-envify "^1.1.0"
object-assign "^4.1.0"
- prop-types "^15.5.10"
+ prop-types "^15.5.6"
react-redux@5.0.6:
version "5.0.6"
@@ -4916,15 +4908,14 @@ react-redux@5.0.6:
loose-envify "^1.1.0"
prop-types "^15.5.10"
-react@15.6.1:
- version "15.6.1"
- resolved "https://registry.yarnpkg.com/react/-/react-15.6.1.tgz#baa8434ec6780bde997cdc380b79cd33b96393df"
+react@16.0.0-rc.3:
+ version "16.0.0-rc.3"
+ resolved "https://registry.yarnpkg.com/react/-/react-16.0.0-rc.3.tgz#4a9df996326ba7185903d9fbed3149765e237e26"
dependencies:
- create-react-class "^15.6.0"
fbjs "^0.8.9"
loose-envify "^1.1.0"
object-assign "^4.1.0"
- prop-types "^15.5.10"
+ prop-types "^15.5.6"
read-config-file@1.1.0:
version "1.1.0"