diff --git a/example/components/CodeSample.react.js b/example/components/CodeSample.react.js
index cec1af60..a41f374a 100644
--- a/example/components/CodeSample.react.js
+++ b/example/components/CodeSample.react.js
@@ -1,21 +1,12 @@
import React from 'react';
+import PropTypes from 'prop-types';
import Markdown from './Markdown';
const START_STR = '/* example-start */';
const END_STR = '/* example-end */';
-const CodeSample = React.createClass({
- propTypes: {
- lang: React.PropTypes.string,
- },
-
- getDefaultProps() {
- return {
- lang: 'jsx',
- };
- },
-
+class CodeSample extends React.Component {
render() {
// Strip out extraneous parts of the code.
const code = this.props.children;
@@ -29,7 +20,16 @@ ${code.slice(startIndex, endIndex)}
\`\`\``}
);
- },
-});
+ }
+}
+
+CodeSample.propTypes = {
+ lang: PropTypes.string,
+};
+
+CodeSample.defaultProps = {
+ lang: 'jsx',
+};
+
export default CodeSample;
diff --git a/example/components/ExampleSection.react.js b/example/components/ExampleSection.react.js
index 96fa7609..0bd015c5 100644
--- a/example/components/ExampleSection.react.js
+++ b/example/components/ExampleSection.react.js
@@ -2,12 +2,14 @@ import React from 'react';
import CodeSample from '../components/CodeSample';
-const ExampleSection = React.createClass({
- getInitialState() {
- return {
+class ExampleSection extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
open: false,
};
- },
+ }
render() {
const {children, code} = this.props;
@@ -33,7 +35,7 @@ const ExampleSection = React.createClass({
{open ? {code} : null}
);
- },
-});
+ }
+}
export default ExampleSection;
diff --git a/example/components/GithubStarsButton.react.js b/example/components/GithubStarsButton.react.js
index ea689bb1..b8d52a04 100644
--- a/example/components/GithubStarsButton.react.js
+++ b/example/components/GithubStarsButton.react.js
@@ -3,11 +3,11 @@ import {findDOMNode} from 'react-dom';
const AUTHOR_REPO = 'ericgio/react-bootstrap-typeahead';
-const GitHubStarsButton = React.createClass({
+class GitHubStarsButton extends React.Component {
componentDidMount() {
const node = findDOMNode(this);
node.dataset.style = window.innerWidth > 480 ? 'mega': null;
- },
+ }
render() {
return (
@@ -21,7 +21,7 @@ const GitHubStarsButton = React.createClass({
Star
);
- },
-});
+ }
+}
export default GitHubStarsButton;
diff --git a/example/components/Markdown.react.js b/example/components/Markdown.react.js
index 62893db4..97319e26 100644
--- a/example/components/Markdown.react.js
+++ b/example/components/Markdown.react.js
@@ -2,7 +2,7 @@ import cx from 'classnames';
import marked from 'marked';
import React from 'react';
-const Markdown = React.createClass({
+class Markdown extends React.Component {
componentWillMount() {
marked.setOptions({
gfm: true,
@@ -16,7 +16,7 @@ const Markdown = React.createClass({
return require('highlight.js').highlightAuto(code).value;
},
});
- },
+ }
render() {
const html = marked.parse(this.props.children);
@@ -27,7 +27,7 @@ const Markdown = React.createClass({
dangerouslySetInnerHTML={{__html: html}}
/>
);
- },
-});
+ }
+}
export default Markdown;
diff --git a/example/components/Page.react.js b/example/components/Page.react.js
index 8843d8b4..b22115f9 100644
--- a/example/components/Page.react.js
+++ b/example/components/Page.react.js
@@ -1,4 +1,6 @@
-import React, {Children, PropTypes} from 'react';
+import React, {Children} from 'react';
+import PropTypes from 'prop-types';
+import createReactClass from 'create-react-class';
import {Col, Jumbotron, NavItem, Row} from 'react-bootstrap';
import Container from './Container';
@@ -8,7 +10,7 @@ import PageMenu from './PageMenu';
import getIdFromTitle from '../util/getIdFromTitle';
-const Page = React.createClass({
+const Page = createReactClass({
getInitialState() {
return {
activeHref: window.location.hash,
diff --git a/example/components/Section.react.js b/example/components/Section.react.js
index cb45b7d2..fdf0a0cd 100644
--- a/example/components/Section.react.js
+++ b/example/components/Section.react.js
@@ -1,4 +1,6 @@
-import React, {PropTypes} from 'react';
+import React from 'react';
+import PropTypes from 'prop-types';
+import createReactClass from 'create-react-class';
import Anchor from './Anchor';
import ScrollSpy from './ScrollSpy';
@@ -6,7 +8,7 @@ import ScrollSpy from './ScrollSpy';
import getIdFromTitle from '../util/getIdFromTitle';
const sectionContainer = Component => (
- React.createClass({
+ createReactClass({
contextTypes: {
onAfter: PropTypes.func.isRequired,
onBefore: PropTypes.func.isRequired,
diff --git a/example/components/Title.react.js b/example/components/Title.react.js
index f876eb44..d05430e2 100644
--- a/example/components/Title.react.js
+++ b/example/components/Title.react.js
@@ -1,4 +1,5 @@
-import React, {PropTypes} from 'react';
+import React from 'react';
+import PropTypes from 'prop-types';
import Anchor from './Anchor';
diff --git a/example/examples/AsyncExample.react.js b/example/examples/AsyncExample.react.js
index 8f07f38c..48920d02 100644
--- a/example/examples/AsyncExample.react.js
+++ b/example/examples/AsyncExample.react.js
@@ -8,14 +8,17 @@ import {AsyncTypeahead} from '../../src/';
require('es6-promise').polyfill();
/* example-start */
-const AsyncExample = React.createClass({
- getInitialState() {
- return {
+class AsyncExample extends React.Component {
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
allowNew: false,
multiple: false,
options: [],
};
- },
+ }
render() {
return (
@@ -30,7 +33,7 @@ const AsyncExample = React.createClass({
{this._renderCheckboxes()}
);
- },
+ }
_renderCheckboxes() {
const checkboxes = [
@@ -47,7 +50,7 @@ const AsyncExample = React.createClass({
{label}
));
- },
+ }
_renderMenuItemChildren(option, props, index) {
return (
@@ -63,12 +66,12 @@ const AsyncExample = React.createClass({
{option.login}
);
- },
+ }
_handleChange(e) {
const {checked, name} = e.target;
this.setState({[name]: checked});
- },
+ }
_handleSearch(query) {
if (!query) {
@@ -78,8 +81,8 @@ const AsyncExample = React.createClass({
fetch(`https://api.github.com/search/users?q=${query}`)
.then(resp => resp.json())
.then(json => this.setState({options: json.items}));
- },
-});
+ }
+}
/* example-end */
export default AsyncExample;
diff --git a/example/examples/BasicBehaviorsExample.react.js b/example/examples/BasicBehaviorsExample.react.js
index ef3d9a07..b43b1341 100644
--- a/example/examples/BasicBehaviorsExample.react.js
+++ b/example/examples/BasicBehaviorsExample.react.js
@@ -6,14 +6,16 @@ import {Typeahead} from '../../src/';
import options from '../../example/exampleData';
/* example-start */
-const BasicBehaviorsExample = React.createClass({
- getInitialState() {
- return {
+class BasicBehaviorsExample extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
disabled: false,
dropup: false,
minLength: 0,
};
- },
+ }
render() {
const {disabled, dropup, emptyLabel, minLength} = this.state;
@@ -56,7 +58,7 @@ const BasicBehaviorsExample = React.createClass({
);
- },
+ }
_handleChange(e) {
const {checked, name} = e.target;
@@ -67,8 +69,8 @@ const BasicBehaviorsExample = React.createClass({
}
this.setState(newState);
- },
-});
+ }
+}
/* example-end */
export default BasicBehaviorsExample;
diff --git a/example/examples/BasicExample.react.js b/example/examples/BasicExample.react.js
index 4cf9ab89..583da35c 100644
--- a/example/examples/BasicExample.react.js
+++ b/example/examples/BasicExample.react.js
@@ -5,12 +5,14 @@ import {Typeahead} from '../../src/';
import options from '../../example/exampleData';
/* example-start */
-const BasicExample = React.createClass({
- getInitialState() {
- return {
+class BasicExample extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
multiple: false,
};
- },
+ }
render() {
const {multiple} = this.state;
@@ -30,8 +32,8 @@ const BasicExample = React.createClass({
);
- },
-});
+ }
+}
/* example-end */
export default BasicExample;
diff --git a/example/examples/BodyContainerExample.react.js b/example/examples/BodyContainerExample.react.js
index 28fd5841..27e0f363 100644
--- a/example/examples/BodyContainerExample.react.js
+++ b/example/examples/BodyContainerExample.react.js
@@ -5,12 +5,13 @@ import {Typeahead} from '../../src/';
import options from '../../example/exampleData';
/* example-start */
-const BodyContainerExample = React.createClass({
- getInitialState() {
- return {
+class BodyContainerExample extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
bodyContainer: false,
};
- },
+ }
render() {
const {bodyContainer} = this.state;
@@ -40,8 +41,8 @@ const BodyContainerExample = React.createClass({
);
- },
-});
+ }
+}
/* example-end */
export default BodyContainerExample;
diff --git a/example/examples/CustomFilteringExample.react.js b/example/examples/CustomFilteringExample.react.js
index dcb4d3b4..34fa81fa 100644
--- a/example/examples/CustomFilteringExample.react.js
+++ b/example/examples/CustomFilteringExample.react.js
@@ -5,12 +5,14 @@ import {Typeahead} from '../../src/';
import options from '../../example/exampleData';
/* example-start */
-const CustomFilteringExample = React.createClass({
- getInitialState() {
- return {
+class CustomFilteringExample extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state ={
filterBy: 'callback',
};
- },
+ }
render() {
const {filterBy} = this.state;
@@ -55,8 +57,8 @@ const CustomFilteringExample = React.createClass({
))}
);
- },
-});
+ }
+}
/* example-end */
export default CustomFilteringExample;
diff --git a/example/examples/CustomSelectionsExample.react.js b/example/examples/CustomSelectionsExample.react.js
index 5340ddd6..1aba65a1 100644
--- a/example/examples/CustomSelectionsExample.react.js
+++ b/example/examples/CustomSelectionsExample.react.js
@@ -2,7 +2,7 @@ import React from 'react';
import {Typeahead} from '../../src/';
/* example-start */
-const CustomSelectionsExample = React.createClass({
+class CustomSelectionsExample extends React.Component {
render() {
return (
);
- },
-});
+ }
+}
/* example-end */
export default CustomSelectionsExample;
diff --git a/example/examples/FilteringExample.react.js b/example/examples/FilteringExample.react.js
index c1b82d5d..288d3147 100644
--- a/example/examples/FilteringExample.react.js
+++ b/example/examples/FilteringExample.react.js
@@ -32,13 +32,15 @@ const options = [
];
/* example-start */
-const FilteringExample = React.createClass({
- getInitialState() {
- return {
+class FilteringExample extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
caseSensitive: false,
ignoreDiacritics: true,
};
- },
+ }
render() {
const {caseSensitive, ignoreDiacritics} = this.state;
@@ -62,8 +64,8 @@ const FilteringExample = React.createClass({
);
- },
-});
+ }
+}
/* example-end */
export default FilteringExample;
diff --git a/example/examples/FormSubmitExample.react.js b/example/examples/FormSubmitExample.react.js
index 52bb44f4..752fb18a 100644
--- a/example/examples/FormSubmitExample.react.js
+++ b/example/examples/FormSubmitExample.react.js
@@ -5,12 +5,14 @@ import {Typeahead} from '../../src/';
import options from '../../example/exampleData';
/* example-start */
-const FormSubmitExample = React.createClass({
- getInitialState() {
- return {
+class FormSubmitExample extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
submitFormOnEnter: true,
};
- },
+ }
render() {
const {submitFormOnEnter} = this.state;
@@ -35,8 +37,8 @@ const FormSubmitExample = React.createClass({
);
- },
-});
+ }
+}
/* example-end */
export default FormSubmitExample;
diff --git a/example/examples/InputSizeExample.react.js b/example/examples/InputSizeExample.react.js
index a2fd4c82..638a9084 100644
--- a/example/examples/InputSizeExample.react.js
+++ b/example/examples/InputSizeExample.react.js
@@ -5,12 +5,14 @@ import {Typeahead} from '../../src/';
import options from '../../example/exampleData';
/* example-start */
-const InputSizeExample = React.createClass({
- getInitialState() {
- return {
+class InputSizeExample extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
bsSize: undefined,
};
- },
+ }
render() {
const {bsSize} = this.state;
@@ -39,8 +41,8 @@ const InputSizeExample = React.createClass({
))}
);
- },
-});
+ }
+}
/* example-end */
export default InputSizeExample;
diff --git a/example/examples/LabelKeyExample.react.js b/example/examples/LabelKeyExample.react.js
index 0d39d700..2f05cfd0 100644
--- a/example/examples/LabelKeyExample.react.js
+++ b/example/examples/LabelKeyExample.react.js
@@ -2,7 +2,7 @@ import React from 'react';
import {Typeahead} from '../../src/';
/* example-start */
-const LabelKeyExample = React.createClass({
+class LabelKeyExample extends React.Component {
render() {
return (
);
- },
-});
+ }
+}
/* example-end */
export default LabelKeyExample;
diff --git a/example/examples/MenuAlignExample.react.js b/example/examples/MenuAlignExample.react.js
index a9ac1598..4c50700e 100644
--- a/example/examples/MenuAlignExample.react.js
+++ b/example/examples/MenuAlignExample.react.js
@@ -5,12 +5,14 @@ import {Typeahead} from '../../src/';
import options from '../../example/exampleData';
/* example-start */
-const MenuAlignExample = React.createClass({
- getInitialState() {
- return {
+class MenuAlignExample extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
align: 'justify',
};
- },
+ }
render() {
const {align} = this.state;
@@ -39,8 +41,8 @@ const MenuAlignExample = React.createClass({
))}
);
- },
-});
+ }
+}
/* example-end */
export default MenuAlignExample;
diff --git a/example/examples/PaginationExample.react.js b/example/examples/PaginationExample.react.js
index 253fbdd5..45b86693 100644
--- a/example/examples/PaginationExample.react.js
+++ b/example/examples/PaginationExample.react.js
@@ -6,12 +6,14 @@ import {Typeahead} from '../../src/';
/* eslint-disable no-console */
/* example-start */
-const LabelKeyExample = React.createClass({
- getInitialState() {
- return {
+class LabelKeyExample extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
paginate: true,
};
- },
+ }
render() {
const {paginate} = this.state;
@@ -31,8 +33,8 @@ const LabelKeyExample = React.createClass({
);
- },
-});
+ }
+}
/* example-end */
/* eslint-disable no-console */
diff --git a/example/examples/PublicMethodsExample.react.js b/example/examples/PublicMethodsExample.react.js
index f059e27a..befb4326 100644
--- a/example/examples/PublicMethodsExample.react.js
+++ b/example/examples/PublicMethodsExample.react.js
@@ -5,7 +5,7 @@ import {Typeahead} from '../../src/';
import options from '../../example/exampleData';
/* example-start */
-const PublicMethodsExample = React.createClass({
+class PublicMethodsExample extends React.Component {
render() {
return (
@@ -35,8 +35,8 @@ const PublicMethodsExample = React.createClass({
);
- },
-});
+ }
+}
/* example-end */
export default PublicMethodsExample;
diff --git a/example/examples/RenderingExample.react.js b/example/examples/RenderingExample.react.js
index c209bb6d..f73a4572 100644
--- a/example/examples/RenderingExample.react.js
+++ b/example/examples/RenderingExample.react.js
@@ -9,12 +9,14 @@ const MenuDivider = props => ;
const MenuHeader = props => ;
/* example-start */
-const RenderingExample = React.createClass({
- getInitialState() {
- return {
+class RenderingExample extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
selectedOption: 'renderMenu',
};
- },
+ }
render() {
const {selectedOption} = this.state;
@@ -57,7 +59,7 @@ const RenderingExample = React.createClass({
))}
);
- },
+ }
_renderMenu(results, menuProps) {
let idx = 0;
@@ -81,7 +83,7 @@ const RenderingExample = React.createClass({
});
return ;
- },
+ }
_renderMenuItemChildren(option, props, index) {
return [
@@ -90,7 +92,7 @@ const RenderingExample = React.createClass({
Population: {option.population.toLocaleString()}
,
];
- },
+ }
_renderToken(option, onRemove, index) {
return (
@@ -100,8 +102,8 @@ const RenderingExample = React.createClass({
{`${option.name} (Pop: ${option.population.toLocaleString()})`}
);
- },
-});
+ }
+}
/* example-end */
export default RenderingExample;
diff --git a/package.json b/package.json
index 8fbf1650..f50797c2 100644
--- a/package.json
+++ b/package.json
@@ -28,12 +28,14 @@
"license": "MIT",
"dependencies": {
"classnames": "^2.2.0",
+ "create-react-class": "^15.5.2",
"invariant": "^2.2.1",
"lodash": "^4.17.2",
+ "prop-types": "^15.5.8",
"react-highlighter": "^0.3.3",
"react-input-autosize": "^1.1.0",
"react-onclickoutside": "^5.7.0",
- "react-overlays": "^0.6.10",
+ "react-overlays": "^0.7.0",
"react-prop-types": "^0.4.0",
"warning": "^3.0.0"
},
@@ -72,7 +74,7 @@
"raw-loader": "^0.5.1",
"react": "^15.2.1",
"react-addons-test-utils": "^15.4.0",
- "react-bootstrap": "^0.30.3",
+ "react-bootstrap": "^0.31.0",
"react-dom": "^15.2.1",
"react-waypoint": "^5.0.3",
"style-loader": "^0.13.1",
diff --git a/src/ClearButton.react.js b/src/ClearButton.react.js
index 4e80db69..47b7fa1f 100644
--- a/src/ClearButton.react.js
+++ b/src/ClearButton.react.js
@@ -1,5 +1,6 @@
import cx from 'classnames';
import React from 'react';
+import PropTypes from 'prop-types';
/**
* CloseButton
@@ -21,7 +22,7 @@ const ClearButton = ({bsSize, className, onClick}) => (
ClearButton.displayName = 'ClearButton';
ClearButton.propTypes = {
- bsSize: React.PropTypes.oneOf(['large', 'lg', 'small', 'sm']),
+ bsSize: PropTypes.oneOf(['large', 'lg', 'small', 'sm']),
};
export default ClearButton;
diff --git a/src/Loader.react.js b/src/Loader.react.js
index 67a7f2c3..beb03e4a 100644
--- a/src/Loader.react.js
+++ b/src/Loader.react.js
@@ -1,5 +1,6 @@
import cx from 'classnames';
import React from 'react';
+import PropTypes from 'prop-types';
const Loader = ({bsSize}) => (
(
);
Loader.propTypes = {
- bsSize: React.PropTypes.oneOf(['large', 'lg', 'small', 'sm']),
+ bsSize: PropTypes.oneOf(['large', 'lg', 'small', 'sm']),
};
export default Loader;
diff --git a/src/Menu.react.js b/src/Menu.react.js
index 1474c9d1..0873fd5a 100644
--- a/src/Menu.react.js
+++ b/src/Menu.react.js
@@ -1,7 +1,8 @@
'use strict';
import cx from 'classnames';
-import React, {Children, PropTypes} from 'react';
+import React, {Children} from 'react';
+import PropTypes from 'prop-types';
import {BaseMenuItem} from './MenuItem.react';
@@ -17,40 +18,8 @@ const BaseMenu = props => (
* Menu component that automatically handles pagination and empty state when
* passed a set of filtered and truncated results.
*/
-const Menu = React.createClass({
- displayName: 'Menu',
-
- propTypes: {
- /**
- * Specify menu alignment. The default value is `justify`, which makes the
- * menu as wide as the input and truncates long values. Specifying `left`
- * or `right` will align the menu to that side and the width will be
- * determined by the length of menu item values.
- */
- align: PropTypes.oneOf(['justify', 'left', 'right']),
- /**
- * Message to display in the menu if there are no valid results.
- */
- emptyLabel: PropTypes.string,
- /**
- * Maximum height of the dropdown menu, in px.
- */
- maxHeight: PropTypes.number,
- /**
- * Prompt displayed when large data sets are paginated.
- */
- paginationText: PropTypes.string,
- },
-
- getDefaultProps() {
- return {
- align: 'justify',
- emptyLabel: 'No matches found.',
- maxHeight: 300,
- paginate: true,
- paginationText: 'Display additional results...',
- };
- },
+class Menu extends React.Component {
+ displayName = 'Menu';
render() {
const {align, children, className, emptyLabel} = this.props;
@@ -78,7 +47,7 @@ const Menu = React.createClass({
{this._renderPaginationMenuItem()}
);
- },
+ }
/**
* Allow user to see more results, if available.
@@ -101,7 +70,7 @@ const Menu = React.createClass({
,
];
}
- },
+ }
_getMenuStyle() {
const {align, dropup, maxHeight, style} = this.props;
@@ -123,7 +92,38 @@ const Menu = React.createClass({
}
return menuStyle;
- },
-});
+ }
+}
+
+Menu.PropTypes = {
+ /**
+ * Specify menu alignment. The default value is `justify`, which makes the
+ * menu as wide as the input and truncates long values. Specifying `left`
+ * or `right` will align the menu to that side and the width will be
+ * determined by the length of menu item values.
+ */
+ align: PropTypes.oneOf(['justify', 'left', 'right']),
+ /**
+ * Message to display in the menu if there are no valid results.
+ */
+ emptyLabel: PropTypes.string,
+ /**
+ * Maximum height of the dropdown menu, in px.
+ */
+ maxHeight: PropTypes.number,
+ /**
+ * Prompt displayed when large data sets are paginated.
+ */
+ paginationText: PropTypes.string,
+};
+
+Menu.defaultProps = {
+ align: 'justify',
+ emptyLabel: 'No matches found.',
+ maxHeight: 300,
+ paginate: true,
+ paginationText: 'Display additional results...',
+};
+
export default Menu;
diff --git a/src/MenuItem.react.js b/src/MenuItem.react.js
index 999938d3..4a0d0a9f 100644
--- a/src/MenuItem.react.js
+++ b/src/MenuItem.react.js
@@ -6,14 +6,14 @@ import React from 'react';
import menuItemContainer from './containers/menuItemContainer';
-const BaseMenuItem = React.createClass({
- displayName: 'BaseMenuItem',
+class BaseMenuItem extends React.Component {
+ displayName = 'BaseMenuItem';
- getDefaultProps() {
- return {
- onClick: noop,
- };
- },
+ constructor(props) {
+ super(props);
+
+ this._handleClick = this._handleClick.bind(this);
+ }
render() {
const {active, children, className, disabled} = this.props;
@@ -29,15 +29,19 @@ const BaseMenuItem = React.createClass({
);
- },
+ }
_handleClick(e) {
const {disabled, onClick} = this.props;
e.preventDefault();
!disabled && onClick(e);
- },
-});
+ }
+}
+
+BaseMenuItem.defaultProps = {
+ onClick: noop,
+};
const MenuItem = menuItemContainer(BaseMenuItem);
diff --git a/src/Overlay.react.js b/src/Overlay.react.js
index 0645580c..bb25b55e 100644
--- a/src/Overlay.react.js
+++ b/src/Overlay.react.js
@@ -1,6 +1,7 @@
import cx from 'classnames';
import {isEqual} from 'lodash';
-import React, {Children, cloneElement, PropTypes} from 'react';
+import React, {Children, cloneElement} from 'react';
+import PropTypes from 'prop-types';
import {findDOMNode} from 'react-dom';
import {Portal} from 'react-overlays';
import componentOrElement from 'react-prop-types/lib/componentOrElement';
@@ -19,35 +20,21 @@ function isBody(container) {
* work for our needs. Specifically, the `Position` component doesn't provide
* the customized placement we need.
*/
-const Overlay = React.createClass({
- displayName: 'Overlay',
-
- propTypes: {
- container: PropTypes.oneOfType([
- componentOrElement,
- PropTypes.func,
- ]).isRequired,
- show: PropTypes.bool,
- target: PropTypes.oneOfType([
- componentOrElement,
- PropTypes.func,
- ]).isRequired,
- },
-
- getDefaultProps() {
- return {
- show: false,
- };
- },
+class Overlay extends React.Component {
+ displayName = 'Overlay';
+
+ constructor(props) {
+ super(props);
+
+ this._updatePosition = this._updatePosition.bind(this);
- getInitialState() {
- return {
+ this.state = {
bottom: 0,
left: 0,
right: 0,
top: 0,
};
- },
+ }
componentDidMount() {
this._mounted = true;
@@ -60,17 +47,17 @@ const Overlay = React.createClass({
window.addEventListener('resize', this._updatePositionThrottled);
window.addEventListener('scroll', this._updatePositionThrottled, true);
- },
+ }
componentWillReceiveProps(nextProps) {
this._updatePositionThrottled();
- },
+ }
componentWillUnmount() {
this._mounted = false;
window.removeEventListener('resize', this._updatePositionThrottled);
window.removeEventListener('scroll', this._updatePositionThrottled);
- },
+ }
render() {
if (!this.props.show) {
@@ -97,7 +84,7 @@ const Overlay = React.createClass({
{child}
);
- },
+ }
_updatePosition() {
// Positioning is only used when body is the container.
@@ -128,7 +115,24 @@ const Overlay = React.createClass({
this.setState(newState);
}
}
- },
-});
+ }
+}
+
+Overlay.propTypes = {
+ container: PropTypes.oneOfType([
+ componentOrElement,
+ PropTypes.func,
+ ]).isRequired,
+ show: PropTypes.bool,
+ target: PropTypes.oneOfType([
+ componentOrElement,
+ PropTypes.func,
+ ]).isRequired,
+};
+
+Overlay.defaultProps = {
+ show: false,
+};
+
export default Overlay;
diff --git a/src/TextInput.react.js b/src/TextInput.react.js
index 513acfd6..40d877f0 100644
--- a/src/TextInput.react.js
+++ b/src/TextInput.react.js
@@ -1,15 +1,11 @@
'use strict';
import cx from 'classnames';
-import React, {PropTypes} from 'react';
+import React from 'react';
+import PropTypes from 'prop-types';
-const TextInput = React.createClass({
- propTypes: {
- /**
- * Specify the size of the input.
- */
- bsSize: PropTypes.oneOf(['large', 'lg', 'small', 'sm']),
- },
+
+class TextInput extends React.Component {
render() {
const {bsSize, className, hasAux, ...otherProps} = this.props;
@@ -26,11 +22,18 @@ const TextInput = React.createClass({
type="text"
/>
);
- },
+ }
getInstance() {
return this._input;
- },
-});
+ }
+}
+
+TextInput.propTypes = {
+ /**
+ * Specify the size of the input.
+ */
+ bsSize: PropTypes.oneOf(['large', 'lg', 'small', 'sm']),
+};
export default TextInput;
diff --git a/src/Token.react.js b/src/Token.react.js
index 641596a1..e2396640 100644
--- a/src/Token.react.js
+++ b/src/Token.react.js
@@ -2,7 +2,8 @@
import cx from 'classnames';
import {noop} from 'lodash';
-import React, {PropTypes} from 'react';
+import React from 'react';
+import PropTypes from 'prop-types';
import tokenContainer from './containers/tokenContainer';
@@ -12,30 +13,14 @@ import tokenContainer from './containers/tokenContainer';
* Individual token component, generally displayed within the TokenizerInput
* component, but can also be rendered on its own.
*/
-const Token = React.createClass({
- displayName: 'Token',
-
- propTypes: {
- /**
- * Handler for removing/deleting the token. If not defined, the token will
- * be rendered in a read-only state.
- */
- onRemove: PropTypes.func,
- selected: PropTypes.bool,
- },
-
- getDefaultProps() {
- return {
- onRemove: noop,
- selected: false,
- };
- },
+class Token extends React.Component {
+ displayName = 'Token';
render() {
return this.props.onRemove && !this.props.disabled ?
this._renderRemoveableToken() :
this._renderToken();
- },
+ }
_renderRemoveableToken() {
const {children, className, onRemove, selected, ...otherProps} = this.props;
@@ -56,7 +41,7 @@ const Token = React.createClass({
);
- },
+ }
_renderToken() {
const {children, className, disabled, href} = this.props;
@@ -75,7 +60,22 @@ const Token = React.createClass({
{children}
);
- },
-});
+ }
+}
+
+Token.propTypes = {
+ /**
+ * Handler for removing/deleting the token. If not defined, the token will
+ * be rendered in a read-only state.
+ */
+ onRemove: PropTypes.func,
+ selected: PropTypes.bool,
+};
+
+Token.defaultProps = {
+ onRemove: noop,
+ selected: false,
+};
+
export default tokenContainer(Token);
diff --git a/src/TokenizerInput.react.js b/src/TokenizerInput.react.js
index 99da3bb3..9cbb4ba2 100644
--- a/src/TokenizerInput.react.js
+++ b/src/TokenizerInput.react.js
@@ -1,7 +1,8 @@
'use strict';
import cx from 'classnames';
-import React, {PropTypes} from 'react';
+import React from 'react';
+import PropTypes from 'prop-types';
import {findDOMNode} from 'react-dom';
import AutosizeInput from 'react-input-autosize';
@@ -16,48 +17,22 @@ import {BACKSPACE} from './utils/keyCode';
* Accepts multiple selections from a Typeahead component and renders them as
* tokens within an input.
*/
-const TokenizerInput = React.createClass({
- displayName: 'TokenizerInput',
+class TokenizerInput extends React.Component {
+ displayName = 'TokenizerInput';
- /**
- * In addition to the propTypes below, the following props are automatically
- * passed down by `Typeahead`:
- *
- * - activeIndex
- * - hasAux
- * - labelKey
- * - onAdd
- * - onBlur
- * - onChange
- * - onClick
- * - onFocus
- * - onKeydown
- * - onRemove
- * - options
- * - selected
- * - value
- */
- propTypes: {
- /**
- * Whether to disable the input and all selections.
- */
- disabled: PropTypes.bool,
- /**
- * Placeholder text for the input.
- */
- placeholder: PropTypes.string,
- /**
- * Provides a hook for customized rendering of tokens when multiple
- * selections are enabled.
- */
- renderToken: PropTypes.func,
- },
-
- getInitialState() {
- return {
+ constructor(props) {
+ super(props);
+
+ this._handleBlur = this._handleBlur.bind(this);
+ this._handleChange = this._handleChange.bind(this);
+ this._handleInputFocus = this._handleInputFocus.bind(this);
+ this._handleKeydown = this._handleKeydown.bind(this);
+ this._renderToken = this._renderToken.bind(this);
+
+ this.state = {
isFocused: false,
};
- },
+ }
render() {
const {bsSize, disabled, hasAux, placeholder, selected, value} = this.props;
@@ -107,15 +82,15 @@ const TokenizerInput = React.createClass({
/>
);
- },
+ }
blur() {
this.refs.input.blur();
- },
+ }
focus() {
this._handleInputFocus();
- },
+ }
_renderToken(option, idx) {
const {disabled, labelKey, onRemove, renderToken} = this.props;
@@ -133,16 +108,16 @@ const TokenizerInput = React.createClass({
{getOptionLabel(option, labelKey)}
);
- },
+ }
_handleBlur(e) {
this.setState({isFocused: false});
this.props.onBlur(e);
- },
+ }
_handleChange(e) {
this.props.onChange(e.target.value);
- },
+ }
_handleKeydown(e) {
switch (e.keyCode) {
@@ -165,7 +140,7 @@ const TokenizerInput = React.createClass({
}
this.props.onKeyDown(e);
- },
+ }
_handleInputFocus(e) {
if (this.props.disabled) {
@@ -177,7 +152,42 @@ const TokenizerInput = React.createClass({
// focus the input.
this.refs.input.focus();
this.setState({isFocused: true});
- },
-});
+ }
+}
+
+/**
+ * In addition to the propTypes below, the following props are automatically
+ * passed down by `Typeahead`:
+ *
+ * - activeIndex
+ * - hasAux
+ * - labelKey
+ * - onAdd
+ * - onBlur
+ * - onChange
+ * - onClick
+ * - onFocus
+ * - onKeydown
+ * - onRemove
+ * - options
+ * - selected
+ * - value
+ */
+TokenizerInput.propTypes = {
+ /**
+ * Whether to disable the input and all selections.
+ */
+ disabled: PropTypes.bool,
+ /**
+ * Placeholder text for the input.
+ */
+ placeholder: PropTypes.string,
+ /**
+ * Provides a hook for customized rendering of tokens when multiple
+ * selections are enabled.
+ */
+ renderToken: PropTypes.func,
+};
+
export default TokenizerInput;
diff --git a/src/Typeahead.react.js b/src/Typeahead.react.js
index d7afefe3..9850f3b0 100644
--- a/src/Typeahead.react.js
+++ b/src/Typeahead.react.js
@@ -3,7 +3,9 @@
import cx from 'classnames';
import {find, isEqual, noop} from 'lodash';
import onClickOutside from 'react-onclickoutside';
-import React, {PropTypes} from 'react';
+import React from 'react';
+import PropTypes from 'prop-types';
+import createReactClass from 'create-react-class';
import ClearButton from './ClearButton.react';
import Loader from './Loader.react';
@@ -25,7 +27,7 @@ import {DOWN, ESC, RETURN, TAB, UP} from './utils/keyCode';
/**
* Typeahead
*/
-const Typeahead = React.createClass({
+const Typeahead = createReactClass({
displayName: 'Typeahead',
propTypes: {
diff --git a/src/TypeaheadInput.react.js b/src/TypeaheadInput.react.js
index 616e7c6f..20f19c65 100644
--- a/src/TypeaheadInput.react.js
+++ b/src/TypeaheadInput.react.js
@@ -2,7 +2,8 @@
import cx from 'classnames';
import {head} from 'lodash';
-import React, {PropTypes} from 'react';
+import React from 'react';
+import PropTypes from 'prop-types';
import TextInput from './TextInput.react';
@@ -13,55 +14,28 @@ import {RIGHT, TAB} from './utils/keyCode';
*
* Handles a single selection from the Typeahead component.
*/
-const TypeaheadInput = React.createClass({
- displayName: 'TypeaheadInput',
+class TypeaheadInput extends React.Component {
+ displayName = 'TypeaheadInput';
- /**
- * In addition to the propTypes below, the following props are automatically
- * passed down by `Typeahead`:
- *
- * - activeIndex
- * - activeItem
- * - hasAux
- * - hintText
- * - labelKey
- * - onAdd
- * - onBlur
- * - onChange
- * - onClick
- * - onFocus
- * - onKeydown
- * - onRemove
- * - selected
- * - value
- */
- propTypes: {
- /**
- * Whether to disable the input and any selection, if present.
- */
- disabled: PropTypes.bool,
- /**
- * Name property for the input.
- */
- name: PropTypes.string,
- /**
- * Placeholder text for the input.
- */
- placeholder: PropTypes.string,
- },
-
- getInitialState() {
- return {
+ constructor(props) {
+ super(props);
+
+ this._handleBlur = this._handleBlur.bind(this);
+ this._handleChange = this._handleChange.bind(this);
+ this._handleInputFocus = this._handleInputFocus.bind(this);
+ this._handleKeydown = this._handleKeydown.bind(this);
+
+ this.state = {
isFocused: false,
};
- },
+ }
componentDidUpdate(prevProps, prevState) {
const {activeIndex, value} = this.props;
if (activeIndex !== prevProps.activeIndex) {
this._input.getInstance().selectionStart = value.length;
}
- },
+ }
render() {
const {
@@ -134,20 +108,20 @@ const TypeaheadInput = React.createClass({
/>
);
- },
+ }
blur() {
this._input.getInstance().blur();
- },
+ }
focus() {
this._handleInputFocus();
- },
+ }
_handleBlur(e) {
this.setState({isFocused: false});
this.props.onBlur(e);
- },
+ }
_handleChange(e) {
// Clear any selections when text is entered.
@@ -155,7 +129,7 @@ const TypeaheadInput = React.createClass({
!!selected.length && onRemove(head(selected));
this.props.onChange(e.target.value);
- },
+ }
/**
* If the containing parent div is focused or clicked, focus the input.
@@ -163,7 +137,7 @@ const TypeaheadInput = React.createClass({
_handleInputFocus(e) {
this.setState({isFocused: true});
this._input.getInstance().focus();
- },
+ }
_handleKeydown(e) {
const {
@@ -201,7 +175,42 @@ const TypeaheadInput = React.createClass({
}
this.props.onKeyDown(e);
- },
-});
+ }
+}
+
+/**
+ * In addition to the propTypes below, the following props are automatically
+ * passed down by `Typeahead`:
+ *
+ * - activeIndex
+ * - activeItem
+ * - hasAux
+ * - hintText
+ * - labelKey
+ * - onAdd
+ * - onBlur
+ * - onChange
+ * - onClick
+ * - onFocus
+ * - onKeydown
+ * - onRemove
+ * - selected
+ * - value
+ */
+TypeaheadInput.propTypes = {
+ /**
+ * Whether to disable the input and any selection, if present.
+ */
+ disabled: PropTypes.bool,
+ /**
+ * Name property for the input.
+ */
+ name: PropTypes.string,
+ /**
+ * Placeholder text for the input.
+ */
+ placeholder: PropTypes.string,
+};
+
export default TypeaheadInput;
diff --git a/src/TypeaheadMenu.react.js b/src/TypeaheadMenu.react.js
index ae0baa4d..b02a6c21 100644
--- a/src/TypeaheadMenu.react.js
+++ b/src/TypeaheadMenu.react.js
@@ -2,7 +2,8 @@
import {pick} from 'lodash';
import Highlight from 'react-highlighter';
-import React, {PropTypes} from 'react';
+import React from 'react';
+import PropTypes from 'prop-types';
import Menu from './Menu.react';
import MenuItem from './MenuItem.react';
@@ -11,36 +12,14 @@ import getOptionLabel from './utils/getOptionLabel';
const MATCH_CLASS = 'bootstrap-typeahead-highlight';
-const TypeaheadMenu = React.createClass({
- displayName: 'TypeaheadMenu',
+class TypeaheadMenu extends React.Component {
+ displayName = 'TypeaheadMenu';
- /**
- * In addition to the propTypes below, the following props are automatically
- * passed down by `Typeahead`:
- *
- * - labelKey
- * - onPaginate
- * - options
- * - paginate
- * - text
- */
- propTypes: {
- /**
- * Provides the ability to specify a prefix before the user-entered text to
- * indicate that the selection will be new. No-op unless `allowNew={true}`.
- */
- newSelectionPrefix: PropTypes.string,
- /**
- * Provides a hook for customized rendering of menu item contents.
- */
- renderMenuItemChildren: PropTypes.func,
- },
-
- getDefaultProps() {
- return {
- newSelectionPrefix: 'New selection: ',
- };
- },
+ constructor(props) {
+ super(props);
+
+ this._renderMenuItem = this._renderMenuItem.bind(this);
+ }
render() {
const menuProps = pick(this.props, [
@@ -60,7 +39,7 @@ const TypeaheadMenu = React.createClass({
{this.props.options.map(this._renderMenuItem)}
);
- },
+ }
_renderMenuItem(option, idx) {
const {
@@ -97,7 +76,34 @@ const TypeaheadMenu = React.createClass({
{getOptionLabel(option, labelKey)}
;
- },
-});
+ }
+}
+
+/**
+ * In addition to the propTypes below, the following props are automatically
+ * passed down by `Typeahead`:
+ *
+ * - labelKey
+ * - onPaginate
+ * - options
+ * - paginate
+ * - text
+ */
+TypeaheadMenu.propTypes = {
+ /**
+ * Provides the ability to specify a prefix before the user-entered text to
+ * indicate that the selection will be new. No-op unless `allowNew={true}`.
+ */
+ newSelectionPrefix: PropTypes.string,
+ /**
+ * Provides a hook for customized rendering of menu item contents.
+ */
+ renderMenuItemChildren: PropTypes.func,
+};
+
+TypeaheadMenu.getDefaultProps = {
+ newSelectionPrefix: 'New selection: ',
+};
+
export default TypeaheadMenu;
diff --git a/src/containers/asyncContainer.js b/src/containers/asyncContainer.js
index 3d79ea85..d75bee54 100644
--- a/src/containers/asyncContainer.js
+++ b/src/containers/asyncContainer.js
@@ -1,5 +1,6 @@
import {debounce} from 'lodash';
-import React, {PropTypes} from 'react';
+import React from 'react';
+import PropTypes from 'prop-types';
const DEFAULT_DELAY_MS = 200;
@@ -12,53 +13,22 @@ const DEFAULT_DELAY_MS = 200;
* - Search prompt and empty results behaviors
*/
const asyncContainer = Typeahead => {
- return React.createClass({
- propTypes: {
- /**
- * Delay, in milliseconds, before performing search.
- */
- delay: PropTypes.number,
- /**
- * Callback to perform when the search is executed.
- */
- onSearch: PropTypes.func.isRequired,
- /**
- * Options to be passed to the typeahead. Will typically be the query
- * results, but can also be initial default options.
- */
- options: PropTypes.array,
- /**
- * Text displayed in the menu when there is no user input.
- */
- promptText: PropTypes.string,
- /**
- * Text displayed in the menu while the request is pending.
- */
- searchText: PropTypes.string,
- /**
- * Whether or not the component should cache query results.
- */
- useCache: PropTypes.bool,
- },
-
- getDefaultProps() {
- return {
- delay: DEFAULT_DELAY_MS,
- minLength: 2,
- options: [],
- promptText: 'Type to search...',
- searchText: 'Searching...',
- useCache: true,
- };
- },
- getInitialState() {
- return {
+ class Container extends React.Component {
+
+ constructor(props) {
+ super(props);
+
+ this._handleChange = this._handleChange.bind(this);
+ this._handleInputChange = this._handleInputChange.bind(this);
+ this._handleSearch = this._handleSearch.bind(this);
+
+ this.state = {
hasSelection: false,
query: '',
requestPending: false,
};
- },
+ }
componentWillMount() {
this._cache = {};
@@ -66,7 +36,7 @@ const asyncContainer = Typeahead => {
this._handleSearch,
this.props.delay
);
- },
+ }
componentWillReceiveProps(nextProps) {
const {options, useCache} = nextProps;
@@ -81,12 +51,12 @@ const asyncContainer = Typeahead => {
}
this.setState({requestPending: false});
- },
+ }
componentWillUnmount() {
this._cache = {};
this._handleSearchDebounced.cancel();
- },
+ }
render() {
const {allowNew, options, useCache, ...props} = this.props;
@@ -111,14 +81,14 @@ const asyncContainer = Typeahead => {
ref={instance => this._instance = instance}
/>
);
- },
+ }
/**
* Make the component instance available.
*/
getInstance() {
return this._instance.getInstance();
- },
+ }
_getEmptyLabel() {
const {
@@ -140,17 +110,17 @@ const asyncContainer = Typeahead => {
}
return emptyLabel;
- },
+ }
_handleChange(selected) {
this.props.onChange && this.props.onChange(selected);
this.setState({hasSelection: !!selected.length});
- },
+ }
_handleInputChange(query) {
this.props.onInputChange && this.props.onInputChange(query);
this._handleSearchDebounced(query);
- },
+ }
_handleSearch(initialQuery) {
const {
@@ -185,8 +155,47 @@ const asyncContainer = Typeahead => {
// Perform the async search.
this.setState({requestPending: true}, () => onSearch(query));
- },
- });
+ }
+ }
+
+ Container.propTypes = {
+ /**
+ * Delay, in milliseconds, before performing search.
+ */
+ delay: PropTypes.number,
+ /**
+ * Callback to perform when the search is executed.
+ */
+ onSearch: PropTypes.func.isRequired,
+ /**
+ * Options to be passed to the typeahead. Will typically be the query
+ * results, but can also be initial default options.
+ */
+ options: PropTypes.array,
+ /**
+ * Text displayed in the menu when there is no user input.
+ */
+ promptText: PropTypes.string,
+ /**
+ * Text displayed in the menu while the request is pending.
+ */
+ searchText: PropTypes.string,
+ /**
+ * Whether or not the component should cache query results.
+ */
+ useCache: PropTypes.bool,
+ };
+
+ Container.defaultProps = {
+ delay: DEFAULT_DELAY_MS,
+ minLength: 2,
+ options: [],
+ promptText: 'Type to search...',
+ searchText: 'Searching...',
+ useCache: true,
+ };
+
+ return Container;
};
export default asyncContainer;
diff --git a/src/containers/menuItemContainer.js b/src/containers/menuItemContainer.js
index bfa0ce68..c4183f9b 100644
--- a/src/containers/menuItemContainer.js
+++ b/src/containers/menuItemContainer.js
@@ -1,11 +1,13 @@
-import React, {PropTypes} from 'react';
+import React from 'react';
+import PropTypes from 'prop-types';
+import createReactClass from 'create-react-class';
import {findDOMNode} from 'react-dom';
import getDisplayName from '../utils/getDisplayName';
import scrollIntoViewIfNeeded from '../utils/scrollIntoViewIfNeeded';
const menuItemContainer = Component => (
- React.createClass({
+ createReactClass({
displayName: `menuItemContainer(${getDisplayName(Component)})`,
propTypes: {
diff --git a/src/containers/tokenContainer.js b/src/containers/tokenContainer.js
index c761edb5..0916db15 100644
--- a/src/containers/tokenContainer.js
+++ b/src/containers/tokenContainer.js
@@ -11,14 +11,22 @@ import {BACKSPACE} from '../utils/keyCode';
* be easily re-used.
*/
const tokenContainer = Component => {
- const WrappedComponent = React.createClass({
- displayName: `tokenContainer(${getDisplayName(Component)})`,
+ class WrappedComponent extends React.Component {
+ displayName = `tokenContainer(${getDisplayName(Component)})`;
- getInitialState() {
- return {
+ constructor(props) {
+ super(props);
+
+ this._handleBlur = this._handleBlur.bind(this);
+ this._handleKeyDown = this._handleKeyDown.bind(this);
+ this._handleRemove = this._handleRemove.bind(this);
+ this._handleSelect = this._handleSelect.bind(this);
+ this.handleClickOutside = this.handleClickOutside.bind(this);
+
+ this.state = {
selected: false,
};
- },
+ }
render() {
const tokenProps = omit(this.props, [
@@ -36,13 +44,13 @@ const tokenContainer = Component => {
onKeyDown={this._handleKeyDown}
/>
);
- },
+ }
_handleBlur(e) {
findDOMNode(this).blur();
this.setState({selected: false});
this.props.disableOnClickOutside && this.props.disableOnClickOutside();
- },
+ }
_handleKeyDown(e) {
switch (e.keyCode) {
@@ -55,25 +63,25 @@ const tokenContainer = Component => {
}
break;
}
- },
+ }
/**
* From `onClickOutside` HOC.
*/
handleClickOutside(e) {
this._handleBlur();
- },
+ }
_handleRemove(e) {
this.props.onRemove && this.props.onRemove();
- },
+ }
_handleSelect(e) {
e.stopPropagation();
this.setState({selected: true});
this.props.enableOnClickOutside && this.props.enableOnClickOutside();
- },
- });
+ }
+ }
return onClickOutside(WrappedComponent);
};
diff --git a/test/ClearButtonSpec.js b/test/ClearButtonSpec.js
index 0d1db67d..7e922ae5 100644
--- a/test/ClearButtonSpec.js
+++ b/test/ClearButtonSpec.js
@@ -1,6 +1,6 @@
import {expect} from 'chai';
import React from 'react';
-import ReactTestUtils from 'react-addons-test-utils';
+import ReactTestUtils from 'react-dom/test-utils';
import ClearButton from '../src/ClearButton';
diff --git a/test/LoaderSpec.js b/test/LoaderSpec.js
index 4cdc7e11..17637aa8 100644
--- a/test/LoaderSpec.js
+++ b/test/LoaderSpec.js
@@ -1,6 +1,6 @@
import {expect} from 'chai';
import React from 'react';
-import ReactTestUtils from 'react-addons-test-utils';
+import ReactTestUtils from 'react-dom/test-utils';
import Loader from '../src/Loader';
diff --git a/test/MenuItemSpec.js b/test/MenuItemSpec.js
index e84f0a2d..04339999 100644
--- a/test/MenuItemSpec.js
+++ b/test/MenuItemSpec.js
@@ -1,6 +1,6 @@
import {expect} from 'chai';
import React from 'react';
-import ReactTestUtils from 'react-addons-test-utils';
+import ReactTestUtils from 'react-dom/test-utils';
import {BaseMenuItem} from '../src/MenuItem';
diff --git a/test/TextInputSpec.js b/test/TextInputSpec.js
index 62983208..38c85411 100644
--- a/test/TextInputSpec.js
+++ b/test/TextInputSpec.js
@@ -1,6 +1,6 @@
import {expect} from 'chai';
import React from 'react';
-import ReactTestUtils from 'react-addons-test-utils';
+import ReactTestUtils from 'react-dom/test-utils';
import TextInput from '../src/TextInput';
diff --git a/test/TokenSpec.js b/test/TokenSpec.js
index fb0bdb38..7d1b2e9c 100644
--- a/test/TokenSpec.js
+++ b/test/TokenSpec.js
@@ -1,7 +1,7 @@
import {expect} from 'chai';
import {noop} from 'lodash';
import React from 'react';
-import ReactTestUtils from 'react-addons-test-utils';
+import ReactTestUtils from 'react-dom/test-utils';
import Token from '../src/Token';
diff --git a/test/TokenizerInputSpec.js b/test/TokenizerInputSpec.js
index e503d0df..15eec852 100644
--- a/test/TokenizerInputSpec.js
+++ b/test/TokenizerInputSpec.js
@@ -1,6 +1,6 @@
import {expect} from 'chai';
import React from 'react';
-import ReactTestUtils from 'react-addons-test-utils';
+import ReactTestUtils from 'react-dom/test-utils';
import TokenizerInput from '../src/TokenizerInput';
diff --git a/test/TypeaheadInputSpec.js b/test/TypeaheadInputSpec.js
index 45a645e2..3ce3a4e1 100644
--- a/test/TypeaheadInputSpec.js
+++ b/test/TypeaheadInputSpec.js
@@ -1,6 +1,6 @@
import {expect} from 'chai';
import React from 'react';
-import ReactTestUtils from 'react-addons-test-utils';
+import ReactTestUtils from 'react-dom/test-utils';
import TypeaheadInput from '../src/TypeaheadInput';
diff --git a/test/TypeaheadMenuSpec.js b/test/TypeaheadMenuSpec.js
index a5b24d95..acd3bac2 100644
--- a/test/TypeaheadMenuSpec.js
+++ b/test/TypeaheadMenuSpec.js
@@ -1,14 +1,16 @@
import {expect} from 'chai';
import {noop, range} from 'lodash';
-import React, {PropTypes} from 'react';
-import ReactTestUtils from 'react-addons-test-utils';
+import React from 'react';
+import PropTypes from 'prop-types';
+import createReactClass from 'create-react-class';
+import ReactTestUtils from 'react-dom/test-utils';
import MenuItem, {BaseMenuItem} from '../src/MenuItem';
import TypeaheadMenu from '../src/TypeaheadMenu';
import options from '../example/exampleData';
-const TypeaheadContext = React.createClass({
+const TypeaheadContext = createReactClass({
childContextTypes: {
activeIndex: PropTypes.number.isRequired,
onActiveItemChange: PropTypes.func.isRequired,
diff --git a/test/TypeaheadSpec.js b/test/TypeaheadSpec.js
index 35758273..b712eac2 100644
--- a/test/TypeaheadSpec.js
+++ b/test/TypeaheadSpec.js
@@ -1,7 +1,7 @@
import {expect} from 'chai';
import {range} from 'lodash';
import React from 'react';
-import ReactTestUtils from 'react-addons-test-utils';
+import ReactTestUtils from 'react-dom/test-utils';
import TokenizerInput from '../src/TokenizerInput';
import Typeahead from '../src/Typeahead';