diff --git a/demo/src/polyfill.js b/demo/src/polyfill.js
index 4826bf56..d09b4a21 100644
--- a/demo/src/polyfill.js
+++ b/demo/src/polyfill.js
@@ -26,6 +26,8 @@ import 'core-js/es7/object'
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
// import 'core-js/es7/reflect'
+import 'element-closest'
+
// CustomEvent() constructor functionality in IE9, IE10, IE11
(function () {
diff --git a/package.json b/package.json
index 5f8aecee..92489a59 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@coreui/react",
- "version": "2.0.4",
+ "version": "2.0.5",
"description": "CoreUI React Bootstrap 4 components",
"license": "MIT",
"author": {
@@ -38,17 +38,19 @@
"@coreui/icons": "0.2.0",
"classnames": "^2.2.6",
"core-js": "^2.5.7",
+ "element-closest": "^2.0.2",
"prop-types": "^15.6.2",
+ "react-onclickout": "^2.0.8",
"react-perfect-scrollbar": "^1.1.1",
"react-router-dom": "^4.3.1",
- "reactstrap": "^6.1.0"
+ "reactstrap": "^6.3.0"
},
"peerDependencies": {
"@coreui/coreui": "^2.0.2",
"react": "16.x"
},
"devDependencies": {
- "babel-eslint": "^8.2.5",
+ "babel-eslint": "^8.2.6",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"eslint": "^4.19.1",
diff --git a/src/Shared/classes.js b/src/Shared/classes.js
index aad4137c..6fc0420b 100644
--- a/src/Shared/classes.js
+++ b/src/Shared/classes.js
@@ -13,3 +13,9 @@ export const asideMenuCssClasses = [
'aside-menu-lg-show',
'aside-menu-xl-show'
];
+
+export const validBreakpoints = [ 'sm', 'md', 'lg', 'xl' ]
+
+export function checkBreakpoint (breakpoint, list) {
+ return list.indexOf(breakpoint) > -1
+}
diff --git a/src/Shared/index.js b/src/Shared/index.js
index f2e9f298..517f2787 100644
--- a/src/Shared/index.js
+++ b/src/Shared/index.js
@@ -1,3 +1,3 @@
-import { sidebarCssClasses, asideMenuCssClasses } from './classes';
+import { sidebarCssClasses, asideMenuCssClasses, validBreakpoints, checkBreakpoint } from './classes';
-export { sidebarCssClasses, asideMenuCssClasses };
+export { sidebarCssClasses, asideMenuCssClasses, validBreakpoints, checkBreakpoint };
diff --git a/src/Shared/toggle-classes.js b/src/Shared/toggle-classes.js
index 6f6205f7..feac9832 100644
--- a/src/Shared/toggle-classes.js
+++ b/src/Shared/toggle-classes.js
@@ -1,6 +1,6 @@
-export default function toggleClasses (toggleClass, classList) {
+export default function toggleClasses (toggleClass, classList, force) {
const level = classList.indexOf(toggleClass)
const removeClassList = classList.slice(0, level)
removeClassList.map((className) => document.body.classList.remove(className))
- document.body.classList.toggle(toggleClass)
+ document.body.classList.toggle(toggleClass, force)
}
diff --git a/src/Sidebar.js b/src/Sidebar.js
index 6896522f..5263bb90 100644
--- a/src/Sidebar.js
+++ b/src/Sidebar.js
@@ -2,6 +2,8 @@ import React, { Component } from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import { sidebarCssClasses } from './Shared';
+import ClickOutHandler from 'react-onclickout'
+import 'element-closest'
const propTypes = {
children: PropTypes.node,
@@ -35,6 +37,7 @@ class AppSidebar extends Component {
this.isMinimized = this.isMinimized.bind(this);
this.isOffCanvas = this.isOffCanvas.bind(this);
this.displayBreakpoint = this.displayBreakpoint.bind(this);
+ this.hideMobile = this.hideMobile.bind(this);
}
componentDidMount() {
@@ -70,6 +73,19 @@ class AppSidebar extends Component {
document.body.classList.add(cssClass);
}
+ hideMobile() {
+ if (document.body.classList.contains('sidebar-show')) {
+ document.body.classList.remove('sidebar-show');
+ }
+ }
+
+ onClickOut(e) {
+ if (!e.target.closest('[data-sidebar-toggler]')) {
+ this.hideMobile();
+ }
+
+ }
+
render() {
const { className, children, tag: Tag, ...attributes } = this.props;
@@ -85,9 +101,11 @@ class AppSidebar extends Component {
// sidebar-nav root
return (
-
- {children}
-
+ {this.onClickOut(e)}}>
+
+ {children}
+
+
);
}
}
diff --git a/src/SidebarToggler.js b/src/SidebarToggler.js
index 3d8f74b7..c0e5497b 100644
--- a/src/SidebarToggler.js
+++ b/src/SidebarToggler.js
@@ -1,7 +1,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
-import { sidebarCssClasses } from './Shared/index';
+import { sidebarCssClasses, validBreakpoints, checkBreakpoint } from './Shared/index';
import toggleClasses from './Shared/toggle-classes';
const propTypes = {
@@ -28,18 +28,16 @@ class AppSidebarToggler extends Component {
sidebarToggle(e) {
e.preventDefault();
+ this.toggle();
+ }
- if (this.props.mobile) {
- document.body.classList.toggle('sidebar-show');
- } else {
- const display = this.props.display;
- const cssTemplate = `sidebar-${display}-show`;
- let [cssClass] = sidebarCssClasses[0];
- if (display && sidebarCssClasses.indexOf(cssTemplate) > -1) {
- cssClass = cssTemplate;
- }
- toggleClasses(cssClass, sidebarCssClasses);
+ toggle(force) {
+ const [display, mobile] = [this.props.display, this.props.mobile]
+ let cssClass = sidebarCssClasses[0]
+ if (!mobile && display && checkBreakpoint(display, validBreakpoints)) {
+ cssClass = `sidebar-${display}-show`
}
+ toggleClasses(cssClass, sidebarCssClasses, force)
}
render() {
@@ -51,7 +49,7 @@ class AppSidebarToggler extends Component {
const classes = classNames(className, 'navbar-toggler');
return (
- this.sidebarToggle(event)}>
+ this.sidebarToggle(event)} data-sidebar-toggler>
{children || }
);
diff --git a/tests/SidebarToggler.test.js b/tests/SidebarToggler.test.js
index 53e1662e..8d673f9f 100644
--- a/tests/SidebarToggler.test.js
+++ b/tests/SidebarToggler.test.js
@@ -13,7 +13,7 @@ configure({ adapter: new Adapter() });
describe('AppSidebarToggler', () => {
it('renders button with class="navbar-toggler"', () => {
expect(render())
- .toContain('')
+ .toContain('')
})
it('should call sidebarToggle', () => {
let component = mount();