Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b411742

Browse filesBrowse files
authored
Merge pull request coreui#34 from coreui/feat-onclickout-sidebar
feat: hide onclick outside mobile sidebar
2 parents 6d519a3 + df2c8cd commit b411742
Copy full SHA for b411742

File tree

8 files changed

+49
-23
lines changed
Filter options

8 files changed

+49
-23
lines changed

‎demo/src/polyfill.js

Copy file name to clipboardExpand all lines: demo/src/polyfill.js
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import 'core-js/es7/object'
2626
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
2727
// import 'core-js/es7/reflect'
2828

29+
import 'element-closest'
30+
2931
// CustomEvent() constructor functionality in IE9, IE10, IE11
3032
(function () {
3133

‎package.json

Copy file name to clipboardExpand all lines: package.json
+5-3Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@coreui/react",
3-
"version": "2.0.4",
3+
"version": "2.0.5",
44
"description": "CoreUI React Bootstrap 4 components",
55
"license": "MIT",
66
"author": {
@@ -38,17 +38,19 @@
3838
"@coreui/icons": "0.2.0",
3939
"classnames": "^2.2.6",
4040
"core-js": "^2.5.7",
41+
"element-closest": "^2.0.2",
4142
"prop-types": "^15.6.2",
43+
"react-onclickout": "^2.0.8",
4244
"react-perfect-scrollbar": "^1.1.1",
4345
"react-router-dom": "^4.3.1",
44-
"reactstrap": "^6.1.0"
46+
"reactstrap": "^6.3.0"
4547
},
4648
"peerDependencies": {
4749
"@coreui/coreui": "^2.0.2",
4850
"react": "16.x"
4951
},
5052
"devDependencies": {
51-
"babel-eslint": "^8.2.5",
53+
"babel-eslint": "^8.2.6",
5254
"enzyme": "^3.3.0",
5355
"enzyme-adapter-react-16": "^1.1.1",
5456
"eslint": "^4.19.1",

‎src/Shared/classes.js

Copy file name to clipboardExpand all lines: src/Shared/classes.js
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,9 @@ export const asideMenuCssClasses = [
1313
'aside-menu-lg-show',
1414
'aside-menu-xl-show'
1515
];
16+
17+
export const validBreakpoints = [ 'sm', 'md', 'lg', 'xl' ]
18+
19+
export function checkBreakpoint (breakpoint, list) {
20+
return list.indexOf(breakpoint) > -1
21+
}

‎src/Shared/index.js

Copy file name to clipboard
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
import { sidebarCssClasses, asideMenuCssClasses } from './classes';
1+
import { sidebarCssClasses, asideMenuCssClasses, validBreakpoints, checkBreakpoint } from './classes';
22

3-
export { sidebarCssClasses, asideMenuCssClasses };
3+
export { sidebarCssClasses, asideMenuCssClasses, validBreakpoints, checkBreakpoint };

‎src/Shared/toggle-classes.js

Copy file name to clipboard
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
export default function toggleClasses (toggleClass, classList) {
1+
export default function toggleClasses (toggleClass, classList, force) {
22
const level = classList.indexOf(toggleClass)
33
const removeClassList = classList.slice(0, level)
44
removeClassList.map((className) => document.body.classList.remove(className))
5-
document.body.classList.toggle(toggleClass)
5+
document.body.classList.toggle(toggleClass, force)
66
}

‎src/Sidebar.js

Copy file name to clipboardExpand all lines: src/Sidebar.js
+21-3Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import React, { Component } from 'react';
22
import classNames from 'classnames';
33
import PropTypes from 'prop-types';
44
import { sidebarCssClasses } from './Shared';
5+
import ClickOutHandler from 'react-onclickout'
6+
import 'element-closest'
57

68
const propTypes = {
79
children: PropTypes.node,
@@ -35,6 +37,7 @@ class AppSidebar extends Component {
3537
this.isMinimized = this.isMinimized.bind(this);
3638
this.isOffCanvas = this.isOffCanvas.bind(this);
3739
this.displayBreakpoint = this.displayBreakpoint.bind(this);
40+
this.hideMobile = this.hideMobile.bind(this);
3841
}
3942

4043
componentDidMount() {
@@ -70,6 +73,19 @@ class AppSidebar extends Component {
7073
document.body.classList.add(cssClass);
7174
}
7275

76+
hideMobile() {
77+
if (document.body.classList.contains('sidebar-show')) {
78+
document.body.classList.remove('sidebar-show');
79+
}
80+
}
81+
82+
onClickOut(e) {
83+
if (!e.target.closest('[data-sidebar-toggler]')) {
84+
this.hideMobile();
85+
}
86+
87+
}
88+
7389
render() {
7490
const { className, children, tag: Tag, ...attributes } = this.props;
7591

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

86102
// sidebar-nav root
87103
return (
88-
<Tag className={classes} {...attributes}>
89-
{children}
90-
</Tag>
104+
<ClickOutHandler onClickOut={(e) => {this.onClickOut(e)}}>
105+
<Tag className={classes} {...attributes}>
106+
{children}
107+
</Tag>
108+
</ClickOutHandler>
91109
);
92110
}
93111
}

‎src/SidebarToggler.js

Copy file name to clipboardExpand all lines: src/SidebarToggler.js
+10-12Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { Component } from 'react';
22
import PropTypes from 'prop-types';
33
import classNames from 'classnames';
4-
import { sidebarCssClasses } from './Shared/index';
4+
import { sidebarCssClasses, validBreakpoints, checkBreakpoint } from './Shared/index';
55
import toggleClasses from './Shared/toggle-classes';
66

77
const propTypes = {
@@ -28,18 +28,16 @@ class AppSidebarToggler extends Component {
2828

2929
sidebarToggle(e) {
3030
e.preventDefault();
31+
this.toggle();
32+
}
3133

32-
if (this.props.mobile) {
33-
document.body.classList.toggle('sidebar-show');
34-
} else {
35-
const display = this.props.display;
36-
const cssTemplate = `sidebar-${display}-show`;
37-
let [cssClass] = sidebarCssClasses[0];
38-
if (display && sidebarCssClasses.indexOf(cssTemplate) > -1) {
39-
cssClass = cssTemplate;
40-
}
41-
toggleClasses(cssClass, sidebarCssClasses);
34+
toggle(force) {
35+
const [display, mobile] = [this.props.display, this.props.mobile]
36+
let cssClass = sidebarCssClasses[0]
37+
if (!mobile && display && checkBreakpoint(display, validBreakpoints)) {
38+
cssClass = `sidebar-${display}-show`
4239
}
40+
toggleClasses(cssClass, sidebarCssClasses, force)
4341
}
4442

4543
render() {
@@ -51,7 +49,7 @@ class AppSidebarToggler extends Component {
5149
const classes = classNames(className, 'navbar-toggler');
5250

5351
return (
54-
<Tag type="button" className={classes} {...attributes} onClick={(event)=>this.sidebarToggle(event)}>
52+
<Tag type="button" className={classes} {...attributes} onClick={(event)=>this.sidebarToggle(event)} data-sidebar-toggler>
5553
{children || <span className="navbar-toggler-icon" />}
5654
</Tag>
5755
);

‎tests/SidebarToggler.test.js

Copy file name to clipboardExpand all lines: tests/SidebarToggler.test.js
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ configure({ adapter: new Adapter() });
1313
describe('AppSidebarToggler', () => {
1414
it('renders button with class="navbar-toggler"', () => {
1515
expect(render(<AppSidebarToggler className="d-lg-none" display="md" mobile />))
16-
.toContain('<button type="button" class="d-lg-none navbar-toggler"><span class="navbar-toggler-icon"></span></button>')
16+
.toContain('<button type="button" class="d-lg-none navbar-toggler" data-sidebar-toggler="true"><span class="navbar-toggler-icon"></span></button>')
1717
})
1818
it('should call sidebarToggle', () => {
1919
let component = mount(<AppSidebarToggler />);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.