8000 Merge pull request #34 from coreui/feat-onclickout-sidebar · junior1296/coreui-react@b411742 · GitHub
[go: up one dir, main page]

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 files
authored
Merge pull request coreui#34 from coreui/feat-onclickout-sidebar
feat: hide onclick outside mobile sidebar
2 parents 6d519a3 + df2c8cd commit b411742

File tree

8 files changed

+49
-23
lines changed

8 files changed

+49
-23
lines changed

demo/src/polyfill.js

Lines 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

Lines 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

Lines 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

Lines 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

Lines 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

Lines 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

Lines 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

Lines 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