diff --git a/src/ControlLabel.js b/src/ControlLabel.js
index 497e51d130..b833daa8dc 100644
--- a/src/ControlLabel.js
+++ b/src/ControlLabel.js
@@ -3,6 +3,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import warning from 'warning';
+import FormGroupContext from './FormGroupContext';
import { bsClass, getClassSet, splitBsProps } from './utils/bootstrapUtils';
const propTypes = {
@@ -17,13 +18,9 @@ const defaultProps = {
srOnly: false
};
-const contextTypes = {
- $bs_formGroup: PropTypes.object
-};
-
class ControlLabel extends React.Component {
render() {
- const formGroup = this.context.$bs_formGroup;
+ const formGroup = this.context;
const controlId = formGroup && formGroup.controlId;
const { htmlFor = controlId, srOnly, className, ...props } = this.props;
@@ -51,6 +48,6 @@ class ControlLabel extends React.Component {
ControlLabel.propTypes = propTypes;
ControlLabel.defaultProps = defaultProps;
-ControlLabel.contextTypes = contextTypes;
+ControlLabel.contextType = FormGroupContext;
export default bsClass('control-label', ControlLabel);
diff --git a/src/FormControl.js b/src/FormControl.js
index 9b5aa7a47a..be7961cecf 100644
--- a/src/FormControl.js
+++ b/src/FormControl.js
@@ -6,6 +6,7 @@ import warning from 'warning';
import FormControlFeedback from './FormControlFeedback';
import FormControlStatic from './FormControlStatic';
+import FormGroupContext from './FormGroupContext';
import {
prefix,
bsClass,
@@ -39,13 +40,9 @@ const defaultProps = {
componentClass: 'input'
};
-const contextTypes = {
- $bs_formGroup: PropTypes.object
-};
-
class FormControl extends React.Component {
render() {
- const formGroup = this.context.$bs_formGroup;
+ const formGroup = this.context;
const controlId = formGroup && formGroup.controlId;
const {
@@ -92,7 +89,7 @@ class FormControl extends React.Component {
FormControl.propTypes = propTypes;
FormControl.defaultProps = defaultProps;
-FormControl.contextTypes = contextTypes;
+FormControl.contextType = FormGroupContext;
FormControl.Feedback = FormControlFeedback;
FormControl.Static = FormControlStatic;
diff --git a/src/FormControlFeedback.js b/src/FormControlFeedback.js
index 0f95fc09c9..f2b7d6525d 100644
--- a/src/FormControlFeedback.js
+++ b/src/FormControlFeedback.js
@@ -1,7 +1,7 @@
import classNames from 'classnames';
import React from 'react';
-import PropTypes from 'prop-types';
+import FormGroupContext from './FormGroupContext';
import Glyphicon from './Glyphicon';
import { bsClass, getClassSet, splitBsProps } from './utils/bootstrapUtils';
@@ -9,10 +9,6 @@ const defaultProps = {
bsRole: 'feedback'
};
-const contextTypes = {
- $bs_formGroup: PropTypes.object
-};
-
class FormControlFeedback extends React.Component {
getGlyph(validationState) {
switch (validationState) {
@@ -50,7 +46,7 @@ class FormControlFeedback extends React.Component {
if (!children) {
return this.renderDefaultFeedback(
- this.context.$bs_formGroup,
+ this.context,
className,
classes,
elementProps
@@ -66,6 +62,6 @@ class FormControlFeedback extends React.Component {
}
FormControlFeedback.defaultProps = defaultProps;
-FormControlFeedback.contextTypes = contextTypes;
+FormControlFeedback.contextType = FormGroupContext;
export default bsClass('form-control-feedback', FormControlFeedback);
diff --git a/src/FormGroup.js b/src/FormGroup.js
index 6ba68e7389..6bfd3da2bc 100644
--- a/src/FormGroup.js
+++ b/src/FormGroup.js
@@ -2,6 +2,7 @@ import classNames from 'classnames';
import React from 'react';
import PropTypes from 'prop-types';
+import FormGroupContext from './FormGroupContext';
import {
bsClass,
bsSizes,
@@ -19,22 +20,7 @@ const propTypes = {
validationState: PropTypes.oneOf(['success', 'warning', 'error', null])
};
-const childContextTypes = {
- $bs_formGroup: PropTypes.object.isRequired
-};
-
class FormGroup extends React.Component {
- getChildContext() {
- const { controlId, validationState } = this.props;
-
- return {
- $bs_formGroup: {
- controlId,
- validationState
- }
- };
- }
-
hasFeedback(children) {
return ValidComponentChildren.some(
children,
@@ -57,15 +43,18 @@ class FormGroup extends React.Component {
}
return (
-
- {children}
-
+
+
+ {children}
+
+
);
}
}
FormGroup.propTypes = propTypes;
-FormGroup.childContextTypes = childContextTypes;
export default bsClass(
'form-group',
diff --git a/src/FormGroupContext.js b/src/FormGroupContext.js
new file mode 100644
index 0000000000..4919156ce4
--- /dev/null
+++ b/src/FormGroupContext.js
@@ -0,0 +1,6 @@
+import React from 'react';
+
+const FormGroupContext = React.createContext(undefined);
+FormGroupContext.displayName = 'FormGroupContext';
+
+export default FormGroupContext;
diff --git a/src/Modal.js b/src/Modal.js
index f0b46d6929..c643d6dc25 100644
--- a/src/Modal.js
+++ b/src/Modal.js
@@ -12,6 +12,7 @@ import elementType from 'prop-types-extra/lib/elementType';
import Fade from './Fade';
import Body from './ModalBody';
+import ModalContext from './ModalContext';
import ModalDialog from './ModalDialog';
import Footer from './ModalFooter';
import Header from './ModalHeader';
@@ -128,12 +129,6 @@ const defaultProps = {
dialogComponentClass: ModalDialog
};
-const childContextTypes = {
- $bs_modal: PropTypes.shape({
- onHide: PropTypes.func
- })
-};
-
/* eslint-disable no-use-before-define, react/no-multi-comp */
function DialogTransition(props) {
return ;
@@ -160,14 +155,6 @@ class Modal extends React.Component {
};
}
- getChildContext() {
- return {
- $bs_modal: {
- onHide: this.props.onHide
- }
- };
- }
-
componentWillUnmount() {
// Clean up the listener if we need to.
this.handleExited();
@@ -257,39 +244,40 @@ class Modal extends React.Component {
const inClassName = show && !animation && 'in';
return (
-
-
-
+
+
+
);
}
}
Modal.propTypes = propTypes;
Modal.defaultProps = defaultProps;
-Modal.childContextTypes = childContextTypes;
Modal.Body = Body;
Modal.Header = Header;
diff --git a/src/ModalContext.js b/src/ModalContext.js
new file mode 100644
index 0000000000..d2a581ae9f
--- /dev/null
+++ b/src/ModalContext.js
@@ -0,0 +1,6 @@
+import React from 'react';
+
+const ModalContext = React.createContext(undefined);
+ModalContext.displayName = 'ModalContext';
+
+export default ModalContext;
diff --git a/src/ModalHeader.js b/src/ModalHeader.js
index 7828629944..d190280e4f 100644
--- a/src/ModalHeader.js
+++ b/src/ModalHeader.js
@@ -5,6 +5,7 @@ import React from 'react';
import { bsClass, getClassSet, splitBsProps } from './utils/bootstrapUtils';
import createChainedFunction from './utils/createChainedFunction';
import CloseButton from './CloseButton';
+import ModalContext from './ModalContext';
// TODO: `aria-label` should be `closeLabel`.
@@ -34,12 +35,6 @@ const defaultProps = {
closeButton: false
};
-const contextTypes = {
- $bs_modal: PropTypes.shape({
- onHide: PropTypes.func
- })
-};
-
class ModalHeader extends React.Component {
render() {
const {
@@ -51,7 +46,7 @@ class ModalHeader extends React.Component {
...props
} = this.props;
- const modal = this.context.$bs_modal;
+ const modal = this.context;
const [bsProps, elementProps] = splitBsProps(props);
@@ -74,6 +69,6 @@ class ModalHeader extends React.Component {
ModalHeader.propTypes = propTypes;
ModalHeader.defaultProps = defaultProps;
-ModalHeader.contextTypes = contextTypes;
+ModalHeader.contextType = ModalContext;
export default bsClass('modal-header', ModalHeader);
diff --git a/src/Nav.js b/src/Nav.js
index 562662a16e..9b20a2476e 100644
--- a/src/Nav.js
+++ b/src/Nav.js
@@ -1,10 +1,12 @@
import classNames from 'classnames';
-import React, { cloneElement } from 'react';
+import React, { cloneElement, useContext } from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import all from 'prop-types-extra/lib/all';
import warning from 'warning';
+import NavbarContext from './NavbarContext';
+import TabContainerContext from './TabContainerContext';
import {
bsClass,
bsStyles,
@@ -95,20 +97,6 @@ const defaultProps = {
stacked: false
};
-const contextTypes = {
- $bs_navbar: PropTypes.shape({
- bsClass: PropTypes.string,
- onSelect: PropTypes.func
- }),
-
- $bs_tabContainer: PropTypes.shape({
- activeKey: PropTypes.any,
- onSelect: PropTypes.func.isRequired,
- getTabId: PropTypes.func.isRequired,
- getPaneId: PropTypes.func.isRequired
- })
-};
-
class Nav extends React.Component {
componentDidUpdate() {
if (!this._needsRefocus) {
@@ -138,7 +126,7 @@ class Nav extends React.Component {
}
getActiveProps() {
- const tabContainer = this.context.$bs_tabContainer;
+ const tabContainer = this.props.tabContainerContext;
if (tabContainer) {
warning(
@@ -280,10 +268,12 @@ class Nav extends React.Component {
pullLeft,
className,
children,
+ navbarContext,
+ tabContainerContext,
...props
} = this.props;
- const tabContainer = this.context.$bs_tabContainer;
+ const tabContainer = tabContainerContext;
const role = propsRole || (tabContainer ? 'tablist' : null);
const { activeKey, activeHref } = this.getActiveProps();
@@ -298,12 +288,12 @@ class Nav extends React.Component {
[prefix(bsProps, 'justified')]: justified
};
- const navbar = propsNavbar != null ? propsNavbar : this.context.$bs_navbar;
+ const navbar = propsNavbar != null ? propsNavbar : navbarContext;
let pullLeftClassName;
let pullRightClassName;
if (navbar) {
- const navbarProps = this.context.$bs_navbar || { bsClass: 'navbar' };
+ const navbarProps = navbarContext || { bsClass: 'navbar' };
classes[prefix(navbarProps, 'nav')] = true;
@@ -353,6 +343,20 @@ class Nav extends React.Component {
Nav.propTypes = propTypes;
Nav.defaultProps = defaultProps;
-Nav.contextTypes = contextTypes;
-export default bsClass('nav', bsStyles(['tabs', 'pills'], Nav));
+const NavWithContext = React.forwardRef((props, ref) => {
+ const navbarContext = useContext(NavbarContext);
+ const tabContainerContext = useContext(TabContainerContext);
+
+ return (
+
+ );
+});
+NavWithContext.displayName = 'NavWithContext';
+
+export default bsClass('nav', bsStyles(['tabs', 'pills'], NavWithContext));
diff --git a/src/Navbar.js b/src/Navbar.js
index 35b904568c..ac293cb6f8 100644
--- a/src/Navbar.js
+++ b/src/Navbar.js
@@ -2,7 +2,7 @@
/* eslint-disable react/no-multi-comp */
import classNames from 'classnames';
-import React from 'react';
+import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import elementType from 'prop-types-extra/lib/elementType';
import uncontrollable from 'uncontrollable';
@@ -10,6 +10,7 @@ import uncontrollable from 'uncontrollable';
import Grid from './Grid';
import NavbarBrand from './NavbarBrand';
import NavbarCollapse from './NavbarCollapse';
+import NavbarContext from './NavbarContext';
import NavbarHeader from './NavbarHeader';
import NavbarToggle from './NavbarToggle';
import {
@@ -109,15 +110,6 @@ const defaultProps = {
collapseOnSelect: false
};
-const childContextTypes = {
- $bs_navbar: PropTypes.shape({
- bsClass: PropTypes.string,
- expanded: PropTypes.bool,
- onToggle: PropTypes.func.isRequired,
- onSelect: PropTypes.func
- })
-};
-
class Navbar extends React.Component {
constructor(props, context) {
super(props, context);
@@ -126,22 +118,6 @@ class Navbar extends React.Component {
this.handleCollapse = this.handleCollapse.bind(this);
}
- getChildContext() {
- const { bsClass, expanded, onSelect, collapseOnSelect } = this.props;
-
- return {
- $bs_navbar: {
- bsClass,
- expanded,
- onToggle: this.handleToggle,
- onSelect: createChainedFunction(
- onSelect,
- collapseOnSelect ? this.handleCollapse : null
- )
- }
- };
- }
-
handleCollapse() {
const { onToggle, expanded } = this.props;
@@ -194,43 +170,57 @@ class Navbar extends React.Component {
[prefix(bsProps, 'static-top')]: staticTop
};
+ const { bsClass, expanded, onSelect, collapseOnSelect } = this.props;
+
+ const navbarContext = {
+ bsClass,
+ expanded,
+ onToggle: this.handleToggle,
+ onSelect: createChainedFunction(
+ onSelect,
+ collapseOnSelect ? this.handleCollapse : null
+ )
+ };
+
return (
-
- {children}
-
+
+
+ {children}
+
+
);
}
}
Navbar.propTypes = propTypes;
Navbar.defaultProps = defaultProps;
-Navbar.childContextTypes = childContextTypes;
setBsClass('navbar', Navbar);
const UncontrollableNavbar = uncontrollable(Navbar, { expanded: 'onToggle' });
function createSimpleWrapper(tag, suffix, displayName) {
- const Wrapper = (
- {
- componentClass: Component = tag,
- className,
- pullRight = false,
- pullLeft = false,
- ...props
- },
- { $bs_navbar: navbarProps = { bsClass: 'navbar' } }
- ) => (
-
- );
+ const Wrapper = ({
+ componentClass: Component = tag,
+ className,
+ pullRight = false,
+ pullLeft = false,
+ ...props
+ }) => {
+ const navbarProps = useContext(NavbarContext) || { bsClass: 'navbar' };
+
+ return (
+
+ );
+ };
Wrapper.displayName = displayName;
@@ -240,12 +230,6 @@ function createSimpleWrapper(tag, suffix, displayName) {
pullLeft: PropTypes.bool
};
- Wrapper.contextTypes = {
- $bs_navbar: PropTypes.shape({
- bsClass: PropTypes.string
- })
- };
-
return Wrapper;
}
diff --git a/src/NavbarBrand.js b/src/NavbarBrand.js
index 8787d7f5fc..acc2fadb78 100644
--- a/src/NavbarBrand.js
+++ b/src/NavbarBrand.js
@@ -1,19 +1,13 @@
import classNames from 'classnames';
import React from 'react';
-import PropTypes from 'prop-types';
+import NavbarContext from './NavbarContext';
import { prefix } from './utils/bootstrapUtils';
-const contextTypes = {
- $bs_navbar: PropTypes.shape({
- bsClass: PropTypes.string
- })
-};
-
class NavbarBrand extends React.Component {
render() {
const { className, children, ...props } = this.props;
- const navbarProps = this.context.$bs_navbar || { bsClass: 'navbar' };
+ const navbarProps = this.context || { bsClass: 'navbar' };
const bsClassName = prefix(navbarProps, 'brand');
@@ -31,6 +25,6 @@ class NavbarBrand extends React.Component {
}
}
-NavbarBrand.contextTypes = contextTypes;
+NavbarBrand.contextType = NavbarContext;
export default NavbarBrand;
diff --git a/src/NavbarCollapse.js b/src/NavbarCollapse.js
index dd47ddbea7..a3c6d3565a 100644
--- a/src/NavbarCollapse.js
+++ b/src/NavbarCollapse.js
@@ -1,20 +1,13 @@
import React from 'react';
-import PropTypes from 'prop-types';
import Collapse from './Collapse';
+import NavbarContext from './NavbarContext';
import { prefix } from './utils/bootstrapUtils';
-const contextTypes = {
- $bs_navbar: PropTypes.shape({
- bsClass: PropTypes.string,
- expanded: PropTypes.bool
- })
-};
-
class NavbarCollapse extends React.Component {
render() {
const { children, ...props } = this.props;
- const navbarProps = this.context.$bs_navbar || { bsClass: 'navbar' };
+ const navbarProps = this.context || { bsClass: 'navbar' };
const bsClassName = prefix(navbarProps, 'collapse');
@@ -26,6 +19,6 @@ class NavbarCollapse extends React.Component {
}
}
-NavbarCollapse.contextTypes = contextTypes;
+NavbarCollapse.contextType = NavbarContext;
export default NavbarCollapse;
diff --git a/src/NavbarContext.js b/src/NavbarContext.js
new file mode 100644
index 0000000000..2643103d9b
--- /dev/null
+++ b/src/NavbarContext.js
@@ -0,0 +1,6 @@
+import React from 'react';
+
+const NavbarContext = React.createContext(undefined);
+NavbarContext.displayName = 'NavbarContext';
+
+export default NavbarContext;
diff --git a/src/NavbarHeader.js b/src/NavbarHeader.js
index 6bc5c4c170..7de2f80b2c 100644
--- a/src/NavbarHeader.js
+++ b/src/NavbarHeader.js
@@ -1,19 +1,13 @@
import classNames from 'classnames';
import React from 'react';
-import PropTypes from 'prop-types';
+import NavbarContext from './NavbarContext';
import { prefix } from './utils/bootstrapUtils';
-const contextTypes = {
- $bs_navbar: PropTypes.shape({
- bsClass: PropTypes.string
- })
-};
-
class NavbarHeader extends React.Component {
render() {
const { className, ...props } = this.props;
- const navbarProps = this.context.$bs_navbar || { bsClass: 'navbar' };
+ const navbarProps = this.context || { bsClass: 'navbar' };
const bsClassName = prefix(navbarProps, 'header');
@@ -21,6 +15,6 @@ class NavbarHeader extends React.Component {
}
}
-NavbarHeader.contextTypes = contextTypes;
+NavbarHeader.contextType = NavbarContext;
export default NavbarHeader;
diff --git a/src/NavbarToggle.js b/src/NavbarToggle.js
index 7b397606b7..b8588b2adc 100644
--- a/src/NavbarToggle.js
+++ b/src/NavbarToggle.js
@@ -2,6 +2,7 @@ import classNames from 'classnames';
import React from 'react';
import PropTypes from 'prop-types';
+import NavbarContext from './NavbarContext';
import { prefix } from './utils/bootstrapUtils';
import createChainedFunction from './utils/createChainedFunction';
@@ -13,18 +14,10 @@ const propTypes = {
children: PropTypes.node
};
-const contextTypes = {
- $bs_navbar: PropTypes.shape({
- bsClass: PropTypes.string,
- expanded: PropTypes.bool,
- onToggle: PropTypes.func.isRequired
- })
-};
-
class NavbarToggle extends React.Component {
render() {
const { onClick, className, children, ...props } = this.props;
- const navbarProps = this.context.$bs_navbar || { bsClass: 'navbar' };
+ const navbarProps = this.context || { bsClass: 'navbar' };
const buttonProps = {
type: 'button',
@@ -53,6 +46,6 @@ class NavbarToggle extends React.Component {
}
NavbarToggle.propTypes = propTypes;
-NavbarToggle.contextTypes = contextTypes;
+NavbarToggle.contextType = NavbarContext;
export default NavbarToggle;
diff --git a/src/Panel.js b/src/Panel.js
index 7a73f50660..80d83da51a 100644
--- a/src/Panel.js
+++ b/src/Panel.js
@@ -12,6 +12,8 @@ import {
} from './utils/bootstrapUtils';
import { State, Style } from './utils/StyleConfig';
import Body from './PanelBody';
+import PanelContext from './PanelContext';
+import PanelGroupContext from './PanelGroupContext';
import Heading from './PanelHeading';
import Title from './PanelTitle';
import Footer from './PanelFooter';
@@ -45,53 +47,9 @@ const propTypes = {
id: PropTypes.string
};
-const contextTypes = {
- $bs_panelGroup: PropTypes.shape({
- getId: PropTypes.func,
- activeKey: PropTypes.any,
- onToggle: PropTypes.func
- })
-};
-
-const childContextTypes = {
- $bs_panel: PropTypes.shape({
- headingId: PropTypes.string,
- bodyId: PropTypes.string,
- bsClass: PropTypes.string,
- onToggle: PropTypes.func,
- expanded: PropTypes.bool
- })
-};
-
class Panel extends React.Component {
- getChildContext() {
- const { eventKey, id } = this.props;
- const idKey = eventKey == null ? id : eventKey;
-
- let ids;
-
- if (idKey !== null) {
- const panelGroup = this.context.$bs_panelGroup;
- const getId = (panelGroup && panelGroup.getId) || defaultGetId;
-
- ids = {
- headingId: getId(idKey, 'heading'),
- bodyId: getId(idKey, 'body')
- };
- }
-
- return {
- $bs_panel: {
- ...ids,
- bsClass: this.props.bsClass,
- expanded: this.getExpanded(),
- onToggle: this.handleToggle
- }
- };
- }
-
getExpanded() {
- const panelGroup = this.context.$bs_panelGroup;
+ const panelGroup = this.context;
if (panelGroup && has.call(panelGroup, 'activeKey')) {
warning(
@@ -108,7 +66,7 @@ class Panel extends React.Component {
}
handleToggle = e => {
- const panelGroup = this.context.$bs_panelGroup;
+ const panelGroup = this.context;
const expanded = !this.getExpanded();
if (panelGroup && panelGroup.onToggle) {
@@ -126,18 +84,41 @@ class Panel extends React.Component {
'expanded'
]);
+ const { eventKey, id } = this.props;
+ const idKey = eventKey == null ? id : eventKey;
+
+ let ids;
+
+ if (idKey !== null) {
+ const panelGroup = this.context;
+ const getId = (panelGroup && panelGroup.getId) || defaultGetId;
+
+ ids = {
+ headingId: getId(idKey, 'heading'),
+ bodyId: getId(idKey, 'body')
+ };
+ }
+
+ const panelContext = {
+ ...ids,
+ bsClass: this.props.bsClass,
+ expanded: this.getExpanded(),
+ onToggle: this.handleToggle
+ };
+
return (
-
- {children}
-
+
+
+ {children}
+
+
);
}
}
Panel.propTypes = propTypes;
-Panel.contextTypes = contextTypes;
-Panel.childContextTypes = childContextTypes;
+Panel.contextType = PanelGroupContext;
const UncontrolledPanel = uncontrollable(
bsClass(
diff --git a/src/PanelBody.js b/src/PanelBody.js
index 9e9d5ac891..32df9c40e3 100644
--- a/src/PanelBody.js
+++ b/src/PanelBody.js
@@ -3,6 +3,7 @@ import React from 'react';
import cn from 'classnames';
import { prefix, splitBsPropsAndOmit, bsClass } from './utils/bootstrapUtils';
import PanelCollapse from './PanelCollapse';
+import PanelContext from './PanelContext';
const propTypes = {
/**
@@ -23,16 +24,10 @@ const defaultProps = {
collapsible: false
};
-const contextTypes = {
- $bs_panel: PropTypes.shape({
- bsClass: PropTypes.string
- })
-};
-
class PanelBody extends React.Component {
render() {
const { children, className, collapsible } = this.props;
- const { bsClass: _bsClass } = this.context.$bs_panel || {};
+ const { bsClass: _bsClass } = this.context || {};
const [bsProps, elementProps] = splitBsPropsAndOmit(this.props, [
'collapsible'
@@ -55,6 +50,6 @@ class PanelBody extends React.Component {
PanelBody.propTypes = propTypes;
PanelBody.defaultProps = defaultProps;
-PanelBody.contextTypes = contextTypes;
+PanelBody.contextType = PanelContext;
export default bsClass('panel', PanelBody);
diff --git a/src/PanelCollapse.js b/src/PanelCollapse.js
index 69d7a4e8ce..d3a2573231 100644
--- a/src/PanelCollapse.js
+++ b/src/PanelCollapse.js
@@ -3,6 +3,7 @@ import React from 'react';
import { prefix, splitBsProps, bsClass } from './utils/bootstrapUtils';
import Collapse from './Collapse';
+import PanelContext from './PanelContext';
const propTypes = {
/**
@@ -31,20 +32,11 @@ const propTypes = {
onExited: PropTypes.func
};
-const contextTypes = {
- $bs_panel: PropTypes.shape({
- headingId: PropTypes.string,
- bodyId: PropTypes.string,
- bsClass: PropTypes.string,
- expanded: PropTypes.bool
- })
-};
-
class PanelCollapse extends React.Component {
render() {
const { children } = this.props;
const { headingId, bodyId, bsClass: _bsClass, expanded } =
- this.context.$bs_panel || {};
+ this.context || {};
const [bsProps, props] = splitBsProps(this.props);
@@ -65,6 +57,6 @@ class PanelCollapse extends React.Component {
}
PanelCollapse.propTypes = propTypes;
-PanelCollapse.contextTypes = contextTypes;
+PanelCollapse.contextType = PanelContext;
export default bsClass('panel', PanelCollapse);
diff --git a/src/PanelContext.js b/src/PanelContext.js
new file mode 100644
index 0000000000..ebfa9c8413
--- /dev/null
+++ b/src/PanelContext.js
@@ -0,0 +1,6 @@
+import React from 'react';
+
+const PanelContext = React.createContext(undefined);
+PanelContext.displayName = 'PanelContext';
+
+export default PanelContext;
diff --git a/src/PanelFooter.js b/src/PanelFooter.js
index 5c7aa061a3..8f9f21b304 100644
--- a/src/PanelFooter.js
+++ b/src/PanelFooter.js
@@ -1,18 +1,13 @@
-import PropTypes from 'prop-types';
import React from 'react';
import cn from 'classnames';
-import { prefix, bsClass, splitBsProps } from './utils/bootstrapUtils';
-const contextTypes = {
- $bs_panel: PropTypes.shape({
- bsClass: PropTypes.string
- })
-};
+import PanelContext from './PanelContext';
+import { prefix, bsClass, splitBsProps } from './utils/bootstrapUtils';
class PanelFooter extends React.Component {
render() {
let { children, className } = this.props;
- let { bsClass: _bsClass } = this.context.$bs_panel || {};
+ let { bsClass: _bsClass } = this.context || {};
const [bsProps, elementProps] = splitBsProps(this.props);
bsProps.bsClass = _bsClass || bsProps.bsClass;
@@ -28,6 +23,6 @@ class PanelFooter extends React.Component {
}
}
-PanelFooter.contextTypes = contextTypes;
+PanelFooter.contextType = PanelContext;
export default bsClass('panel', PanelFooter);
diff --git a/src/PanelGroup.js b/src/PanelGroup.js
index a7fd8466d8..01cd6c685f 100644
--- a/src/PanelGroup.js
+++ b/src/PanelGroup.js
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import React, { cloneElement } from 'react';
import uncontrollable from 'uncontrollable';
+import PanelGroupContext from './PanelGroupContext';
import {
bsClass,
getClassSet,
@@ -56,40 +57,7 @@ const defaultProps = {
accordion: false
};
-const childContextTypes = {
- $bs_panelGroup: PropTypes.shape({
- getId: PropTypes.func,
- headerRole: PropTypes.string,
- panelRole: PropTypes.string,
- activeKey: PropTypes.any,
- onToggle: PropTypes.func
- })
-};
-
class PanelGroup extends React.Component {
- getChildContext() {
- const { activeKey, accordion, generateChildId, id } = this.props;
- let getId = null;
-
- if (accordion) {
- getId =
- generateChildId ||
- ((key, type) => (id ? `${id}-${type}-${key}` : null));
- }
-
- return {
- $bs_panelGroup: {
- getId,
- headerRole: 'tab',
- panelRole: 'tabpanel',
- ...(accordion && {
- activeKey,
- onToggle: this.handleSelect
- })
- }
- };
- }
-
handleSelect = (key, expanded, e) => {
if (expanded) {
this.props.onSelect(key, e);
@@ -112,21 +80,41 @@ class PanelGroup extends React.Component {
const classes = getClassSet(bsProps);
+ const { activeKey, generateChildId, id } = this.props;
+ let getId = null;
+
+ if (accordion) {
+ getId =
+ generateChildId ||
+ ((key, type) => (id ? `${id}-${type}-${key}` : null));
+ }
+
+ const panelGroupContext = {
+ getId,
+ headerRole: 'tab',
+ panelRole: 'tabpanel',
+ ...(accordion && {
+ activeKey,
+ onToggle: this.handleSelect
+ })
+ };
+
return (
-
- {ValidComponentChildren.map(children, child =>
- cloneElement(child, {
- bsStyle: child.props.bsStyle || bsProps.bsStyle
- })
- )}
-
+
+
+ {ValidComponentChildren.map(children, child =>
+ cloneElement(child, {
+ bsStyle: child.props.bsStyle || bsProps.bsStyle
+ })
+ )}
+
+
);
}
}
PanelGroup.propTypes = propTypes;
PanelGroup.defaultProps = defaultProps;
-PanelGroup.childContextTypes = childContextTypes;
export default uncontrollable(bsClass('panel-group', PanelGroup), {
activeKey: 'onSelect'
diff --git a/src/PanelGroupContext.js b/src/PanelGroupContext.js
new file mode 100644
index 0000000000..3454451175
--- /dev/null
+++ b/src/PanelGroupContext.js
@@ -0,0 +1,6 @@
+import React from 'react';
+
+const PanelGroupContext = React.createContext(undefined);
+PanelGroupContext.displayName = 'PanelGroupContext';
+
+export default PanelGroupContext;
diff --git a/src/PanelHeading.js b/src/PanelHeading.js
index ddb61ffeac..17a69951a2 100644
--- a/src/PanelHeading.js
+++ b/src/PanelHeading.js
@@ -1,8 +1,8 @@
-import PropTypes from 'prop-types';
import React from 'react';
import cn from 'classnames';
import elementType from 'react-prop-types/lib/elementType';
+import PanelContext from './PanelContext';
import { prefix, bsClass, splitBsProps } from './utils/bootstrapUtils';
const propTypes = {
@@ -13,13 +13,6 @@ const defaultProps = {
componentClass: 'div'
};
-const contextTypes = {
- $bs_panel: PropTypes.shape({
- headingId: PropTypes.string,
- bsClass: PropTypes.string
- })
-};
-
class PanelHeading extends React.Component {
render() {
const {
@@ -28,7 +21,7 @@ class PanelHeading extends React.Component {
componentClass: Component,
...props
} = this.props;
- const { headingId, bsClass: _bsClass } = this.context.$bs_panel || {};
+ const { headingId, bsClass: _bsClass } = this.context || {};
const [bsProps, elementProps] = splitBsProps(props);
bsProps.bsClass = _bsClass || bsProps.bsClass;
@@ -51,6 +44,6 @@ class PanelHeading extends React.Component {
PanelHeading.propTypes = propTypes;
PanelHeading.defaultProps = defaultProps;
-PanelHeading.contextTypes = contextTypes;
+PanelHeading.contextType = PanelContext;
export default bsClass('panel', PanelHeading);
diff --git a/src/PanelTitle.js b/src/PanelTitle.js
index 2d102324b3..7aa4bacf7e 100644
--- a/src/PanelTitle.js
+++ b/src/PanelTitle.js
@@ -3,8 +3,9 @@ import PropTypes from 'prop-types';
import React from 'react';
import elementType from 'react-prop-types/lib/elementType';
-import { prefix, splitBsProps, bsClass } from './utils/bootstrapUtils';
+import PanelContext from './PanelContext';
import PanelToggle from './PanelToggle';
+import { prefix, splitBsProps, bsClass } from './utils/bootstrapUtils';
const propTypes = {
componentClass: elementType,
@@ -15,12 +16,6 @@ const propTypes = {
toggle: PropTypes.bool
};
-const contextTypes = {
- $bs_panel: PropTypes.shape({
- bsClass: PropTypes.string
- })
-};
-
const defaultProps = {
componentClass: 'div'
};
@@ -35,7 +30,7 @@ class PanelTitle extends React.Component {
...props
} = this.props;
- const { bsClass: _bsClass } = this.context.$bs_panel || {};
+ const { bsClass: _bsClass } = this.context || {};
const [bsProps, elementProps] = splitBsProps(props);
bsProps.bsClass = _bsClass || bsProps.bsClass;
@@ -57,6 +52,6 @@ class PanelTitle extends React.Component {
PanelTitle.propTypes = propTypes;
PanelTitle.defaultProps = defaultProps;
-PanelTitle.contextTypes = contextTypes;
+PanelTitle.contextType = PanelContext;
export default bsClass('panel', PanelTitle);
diff --git a/src/PanelToggle.js b/src/PanelToggle.js
index cb8605317c..2e0a20036f 100644
--- a/src/PanelToggle.js
+++ b/src/PanelToggle.js
@@ -2,6 +2,8 @@ import PropTypes from 'prop-types';
import React from 'react';
import classNames from 'classnames';
import elementType from 'react-prop-types/lib/elementType';
+
+import PanelContext from './PanelContext';
import SafeAnchor from './SafeAnchor';
import createChainedFunction from './utils/createChainedFunction';
@@ -22,14 +24,6 @@ const defaultProps = {
componentClass: SafeAnchor
};
-const contextTypes = {
- $bs_panel: PropTypes.shape({
- bodyId: PropTypes.string,
- onToggle: PropTypes.func,
- expanded: PropTypes.bool
- })
-};
-
class PanelToggle extends React.Component {
constructor(...args) {
super(...args);
@@ -38,7 +32,7 @@ class PanelToggle extends React.Component {
}
handleToggle(event) {
- const { onToggle } = this.context.$bs_panel || {};
+ const { onToggle } = this.context || {};
if (onToggle) {
onToggle(event);
@@ -47,7 +41,7 @@ class PanelToggle extends React.Component {
render() {
const { onClick, className, componentClass, ...props } = this.props;
- const { expanded, bodyId } = this.context.$bs_panel || {};
+ const { expanded, bodyId } = this.context || {};
const Component = componentClass;
props.onClick = createChainedFunction(onClick, this.handleToggle);
@@ -65,6 +59,6 @@ class PanelToggle extends React.Component {
PanelToggle.propTypes = propTypes;
PanelToggle.defaultProps = defaultProps;
-PanelToggle.contextTypes = contextTypes;
+PanelToggle.contextType = PanelContext;
export default PanelToggle;
diff --git a/src/TabContainer.js b/src/TabContainer.js
index deebb182ea..a36058d6dd 100644
--- a/src/TabContainer.js
+++ b/src/TabContainer.js
@@ -2,6 +2,8 @@ import React from 'react';
import PropTypes from 'prop-types';
import uncontrollable from 'uncontrollable';
+import TabContainerContext from './TabContainerContext';
+
const TAB = 'tab';
const PANE = 'pane';
@@ -58,44 +60,34 @@ const propTypes = {
activeKey: PropTypes.any
};
-const childContextTypes = {
- $bs_tabContainer: PropTypes.shape({
- activeKey: PropTypes.any,
- onSelect: PropTypes.func.isRequired,
- getTabId: PropTypes.func.isRequired,
- getPaneId: PropTypes.func.isRequired
- })
-};
-
class TabContainer extends React.Component {
- getChildContext() {
+ render() {
+ const { children, ...props } = this.props;
+
const { activeKey, onSelect, generateChildId, id } = this.props;
const getId =
generateChildId || ((key, type) => (id ? `${id}-${type}-${key}` : null));
- return {
- $bs_tabContainer: {
- activeKey,
- onSelect,
- getTabId: key => getId(key, TAB),
- getPaneId: key => getId(key, PANE)
- }
+ const tabContainerContext = {
+ activeKey,
+ onSelect,
+ getTabId: key => getId(key, TAB),
+ getPaneId: key => getId(key, PANE)
};
- }
-
- render() {
- const { children, ...props } = this.props;
delete props.generateChildId;
delete props.onSelect;
delete props.activeKey;
- return React.cloneElement(React.Children.only(children), props);
+ return (
+
+ {React.cloneElement(React.Children.only(children), props)}
+
+ );
}
}
TabContainer.propTypes = propTypes;
-TabContainer.childContextTypes = childContextTypes;
export default uncontrollable(TabContainer, { activeKey: 'onSelect' });
diff --git a/src/TabContainerContext.js b/src/TabContainerContext.js
new file mode 100644
index 0000000000..bc14745edf
--- /dev/null
+++ b/src/TabContainerContext.js
@@ -0,0 +1,6 @@
+import React from 'react';
+
+const TabContainerContext = React.createContext(undefined);
+TabContainerContext.displayName = 'TabContainerContext';
+
+export default TabContainerContext;
diff --git a/src/TabContent.js b/src/TabContent.js
index a5b3bbc8c0..4ab8ccbcb7 100644
--- a/src/TabContent.js
+++ b/src/TabContent.js
@@ -3,6 +3,8 @@ import React from 'react';
import PropTypes from 'prop-types';
import elementType from 'prop-types-extra/lib/elementType';
+import TabContainerContext from './TabContainerContext';
+import TabContentContext from './TabContentContext';
import {
bsClass as setBsClass,
prefix,
@@ -37,25 +39,6 @@ const defaultProps = {
unmountOnExit: false
};
-const contextTypes = {
- $bs_tabContainer: PropTypes.shape({
- activeKey: PropTypes.any
- })
-};
-
-const childContextTypes = {
- $bs_tabContent: PropTypes.shape({
- bsClass: PropTypes.string,
- animation: PropTypes.oneOfType([PropTypes.bool, elementType]),
- activeKey: PropTypes.any,
- mountOnEnter: PropTypes.bool,
- unmountOnExit: PropTypes.bool,
- onPaneEnter: PropTypes.func.isRequired,
- onPaneExited: PropTypes.func.isRequired,
- exiting: PropTypes.bool.isRequired
- })
-};
-
class TabContent extends React.Component {
constructor(props, context) {
super(props, context);
@@ -72,31 +55,6 @@ class TabContent extends React.Component {
};
}
- getChildContext() {
- const { bsClass, animation, mountOnEnter, unmountOnExit } = this.props;
-
- const stateActiveKey = this.state.activeKey;
- const containerActiveKey = this.getContainerActiveKey();
-
- const activeKey =
- stateActiveKey != null ? stateActiveKey : containerActiveKey;
- const exiting =
- stateActiveKey != null && stateActiveKey !== containerActiveKey;
-
- return {
- $bs_tabContent: {
- bsClass,
- animation,
- activeKey,
- mountOnEnter,
- unmountOnExit,
- onPaneEnter: this.handlePaneEnter,
- onPaneExited: this.handlePaneExited,
- exiting
- }
- };
- }
-
UNSAFE_componentWillReceiveProps(nextProps) {
if (!nextProps.animation && this.state.activeChild) {
this.setState({ activeKey: null, activeChild: null });
@@ -108,7 +66,7 @@ class TabContent extends React.Component {
}
getContainerActiveKey() {
- const tabContainer = this.context.$bs_tabContainer;
+ const tabContainer = this.context;
return tabContainer && tabContainer.activeKey;
}
@@ -156,18 +114,40 @@ class TabContent extends React.Component {
'unmountOnExit'
]);
+ const { bsClass, animation, mountOnEnter, unmountOnExit } = this.props;
+
+ const stateActiveKey = this.state.activeKey;
+ const containerActiveKey = this.getContainerActiveKey();
+
+ const activeKey =
+ stateActiveKey != null ? stateActiveKey : containerActiveKey;
+ const exiting =
+ stateActiveKey != null && stateActiveKey !== containerActiveKey;
+
+ const tabContentContext = {
+ bsClass,
+ animation,
+ activeKey,
+ mountOnEnter,
+ unmountOnExit,
+ onPaneEnter: this.handlePaneEnter,
+ onPaneExited: this.handlePaneExited,
+ exiting
+ };
+
return (
-
+
+
+
);
}
}
TabContent.propTypes = propTypes;
TabContent.defaultProps = defaultProps;
-TabContent.contextTypes = contextTypes;
-TabContent.childContextTypes = childContextTypes;
+TabContent.contextType = TabContainerContext;
export default setBsClass('tab', TabContent);
diff --git a/src/TabContentContext.js b/src/TabContentContext.js
new file mode 100644
index 0000000000..7e2c47c6d7
--- /dev/null
+++ b/src/TabContentContext.js
@@ -0,0 +1,6 @@
+import React from 'react';
+
+const TabContentContext = React.createContext(undefined);
+TabContentContext.displayName = 'TabContentContext';
+
+export default TabContentContext;
diff --git a/src/TabPane.js b/src/TabPane.js
index e69bf15aba..08895bdb2b 100644
--- a/src/TabPane.js
+++ b/src/TabPane.js
@@ -4,6 +4,8 @@ import PropTypes from 'prop-types';
import elementType from 'prop-types-extra/lib/elementType';
import warning from 'warning';
+import TabContainerContext from './TabContainerContext';
+import TabContentContext from './TabContentContext';
import {
bsClass,
getClassSet,
@@ -81,31 +83,6 @@ const propTypes = {
unmountOnExit: PropTypes.bool
};
-const contextTypes = {
- $bs_tabContainer: PropTypes.shape({
- getTabId: PropTypes.func,
- getPaneId: PropTypes.func
- }),
- $bs_tabContent: PropTypes.shape({
- bsClass: PropTypes.string,
- animation: PropTypes.oneOfType([PropTypes.bool, elementType]),
- activeKey: PropTypes.any,
- mountOnEnter: PropTypes.bool,
- unmountOnExit: PropTypes.bool,
- onPaneEnter: PropTypes.func.isRequired,
- onPaneExited: PropTypes.func.isRequired,
- exiting: PropTypes.bool.isRequired
- })
-};
-
-/**
- * We override the `` context so `