Skip to content

Commit

Permalink
Merge pull request #34 from coreui/feat-onclickout-sidebar
Browse files Browse the repository at this point in the history
feat: hide onclick outside mobile sidebar
  • Loading branch information
xidedix authored Jul 20, 2018
2 parents 6d519a3 + df2c8cd commit b411742
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 23 deletions.
2 changes: 2 additions & 0 deletions demo/src/polyfill.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {

Expand Down
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@coreui/react",
"version": "2.0.4",
"version": "2.0.5",
"description": "CoreUI React Bootstrap 4 components",
"license": "MIT",
"author": {
Expand Down Expand Up @@ -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",
Expand Down
6 changes: 6 additions & 0 deletions src/Shared/classes.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
4 changes: 2 additions & 2 deletions src/Shared/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { sidebarCssClasses, asideMenuCssClasses } from './classes';
import { sidebarCssClasses, asideMenuCssClasses, validBreakpoints, checkBreakpoint } from './classes';

export { sidebarCssClasses, asideMenuCssClasses };
export { sidebarCssClasses, asideMenuCssClasses, validBreakpoints, checkBreakpoint };
4 changes: 2 additions & 2 deletions src/Shared/toggle-classes.js
Original file line number Diff line number Diff line change
@@ -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)
}
24 changes: 21 additions & 3 deletions src/Sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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;

Expand All @@ -85,9 +101,11 @@ class AppSidebar extends Component {

// sidebar-nav root
return (
<Tag className={classes} {...attributes}>
{children}
</Tag>
<ClickOutHandler onClickOut={(e) => {this.onClickOut(e)}}>
<Tag className={classes} {...attributes}>
{children}
</Tag>
</ClickOutHandler>
);
}
}
Expand Down
22 changes: 10 additions & 12 deletions src/SidebarToggler.js
Original file line number Diff line number Diff line change
@@ -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 = {
Expand All @@ -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() {
Expand All @@ -51,7 +49,7 @@ class AppSidebarToggler extends Component {
const classes = classNames(className, 'navbar-toggler');

return (
<Tag type="button" className={classes} {...attributes} onClick={(event)=>this.sidebarToggle(event)}>
<Tag type="button" className={classes} {...attributes} onClick={(event)=>this.sidebarToggle(event)} data-sidebar-toggler>
{children || <span className="navbar-toggler-icon" />}
</Tag>
);
Expand Down
2 changes: 1 addition & 1 deletion tests/SidebarToggler.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ configure({ adapter: new Adapter() });
describe('AppSidebarToggler', () => {
it('renders button with class="navbar-toggler"', () => {
expect(render(<AppSidebarToggler className="d-lg-none" display="md" mobile />))
.toContain('<button type="button" class="d-lg-none navbar-toggler"><span class="navbar-toggler-icon"></span></button>')
.toContain('<button type="button" class="d-lg-none navbar-toggler" data-sidebar-toggler="true"><span class="navbar-toggler-icon"></span></button>')
})
it('should call sidebarToggle', () => {
let component = mount(<AppSidebarToggler />);
Expand Down

0 comments on commit b411742

Please sign in to comment.