11<template >
2- <div :class =" sidebarClasses" v-on-clickaway = " hideMobile " >
2+ <div :class =" sidebarClasses" >
33 <slot >Sidebar</slot >
44 </div >
55</template >
6- <script >
7- import { mixin as clickaway } from ' vue-clickaway2'
8- import { hideMobile } from ' ./hideMobile'
96
7+ <script >
8+ import elementResizeDetectorMaker from ' element-resize-detector'
9+ import { getStyle } from ' @coreui/coreui/dist/js/coreui-utilities'
1010export default {
1111 name: ' CSidebar' ,
12- mixins: [clickaway, hideMobile],
1312 props: {
1413 fixed: Boolean ,
1514 minimize: Boolean ,
16- display: {
17- type: [Boolean , String ],
15+ show: {
16+ type: Boolean ,
17+ default: true
18+ },
19+ mobileShow: Boolean ,
20+ noHideOnMobileClick: Boolean ,
21+ breakpoint: {
22+ type: [String , Boolean ],
1823 default: ' lg' ,
19- validator : val => [true , false , ' sm' , ' md' , ' lg' , ' xl' ].includes (val)
24+ validator : val => [false , ' sm' , ' md' , ' lg' , ' xl' ].includes (val)
2025 },
21- mobile: Boolean ,
2226 aside: Boolean ,
2327 light: Boolean
2428 },
@@ -31,36 +35,110 @@ export default {
3135 },
3236 data () {
3337 return {
34- displayed: this .display ,
35- minimized: this .minimize
38+ open: this .show ,
39+ mobileOpen: this .mobileShow ,
40+ minimized: this .initialMinimize ,
41+ erd: elementResizeDetectorMaker (),
42+ bodyWidth: undefined ,
3643 }
3744 },
3845 mounted () {
46+ this .erd .listenTo (document .body , (el ) => this .bodyWidth = el .clientWidth )
47+
3948 this .$root .$on (` c-${ this .mode } -toggle-minimize` , () => {
40- this .minimized = ! this . minimized
49+ this .switchState ( ' minimized' )
4150 })
4251 this .$root .$on (` c-${ this .mode } -toggle` , () => {
43- this .displayed = this .displayed ? false : this .display || true
52+ if (this .isOnMobile ) {
53+ this .switchState (' mobileOpen' )
54+ } else {
55+ this .switchState (' open' )
56+ }
4457 })
4558 },
59+ watch: {
60+ show (val , oldVal ) {
61+ if (val !== oldVal && val !== this .open ) {
62+ this .switchState (' open' )
63+ }
64+ },
65+ mobileShow (val , oldVal ) {
66+ if (val !== oldVal && val !== this .mobileOpen ) {
67+ this .switchState (' mobileOpen' )
68+ }
69+ },
70+ minimize (val , oldVal ) {
71+ if (val !== oldVal && val !== this .minimized ) {
72+ this .switchState (' minimized' )
73+ }
74+ },
75+ isOnMobile: {
76+ immediate: true ,
77+ handler (val , oldVal ) {
78+ if (val === true && val !== oldVal) {
79+ document .body .addEventListener (' click' , this .mobileClick )
80+ } else if (oldVal === true ) {
81+ document .body .removeEventListener (' click' , this .mobileClick )
82+ }
83+ }
84+ }
85+ },
4686 computed: {
4787 mode () {
4888 return this .aside ? ' aside' : ' sidebar'
4989 },
50- breakpoint () {
51- return this .displayed === true || this .mobile ? ' ' : ' -' + this .display
90+ isVisible () {
91+ if (this .bodyWidth ) {
92+ return this .isOnMobile ? this .mobileOpen : this .open
93+ }
94+ return false
5295 },
5396 sidebarClasses () {
5497 return [
55- ' c-sidebar' ,
56- ` c-sidebar-${ this .light ? ' light' : ' dark' } ` ,
57- {
58- [` c-sidebar${ this .breakpoint } -show` ]: this .displayed ,
59- ' c-sidebar-fixed' : this .fixed ,
60- ' c-sidebar-minimized' : this .minimized ,
61- ' c-sidebar-right' : this .aside
62- }
63- ]
98+ this .displayClass ,
99+ ' c-sidebar' ,
100+ ` c-sidebar-${ this .light ? ' light' : ' dark' } ` ,
101+ {
102+ ' c-sidebar-show' : this .isOnMobile && this .mobileOpen ,
103+ [` c-sidebar-${ this .breakpoint } -show` ]: this .open ,
104+ ' c-sidebar-fixed' : this .fixed ,
105+ ' c-sidebar-minimized' : this .minimized ,
106+ ' c-sidebar-right' : this .aside
107+ }
108+ ]
109+ },
110+ breakpoints () {
111+ return {
112+ ' sm' : getStyle (' --breakpoint-sm' ) || ' 576px' ,
113+ ' md' : getStyle (' --breakpoint-md' ) || ' 768px' ,
114+ ' lg' : getStyle (' --breakpoint-lg' ) || ' 992px' ,
115+ ' xl' : getStyle (' --breakpoint-xl' ) || ' 1200px'
116+ }
117+ },
118+ isOnMobile () {
119+ const mobileWidth = parseFloat (this .breakpoints [this .breakpoint ]) || 0
120+ return this .bodyWidth && (this .bodyWidth < mobileWidth)
121+ }
122+ },
123+ methods: {
124+ mobileClick (event ) {
125+ if (! this .mobileOpen || this .noHideOnMobileClick ) {
126+ return
127+ }
128+ const classList = Array .from (event .target .classList ).join ()
129+ const clickedOutsideSidebar = ! this .$el .contains (event .target )
130+ if (
131+ (clickedOutsideSidebar && ! classList .includes (' c-header-toggler' )) || (! clickedOutsideSidebar && event .target .tagName === ' A' )
132+ ) {
133+ this .switchState (' mobileOpen' )
134+ }
135+ },
136+ switchState (variable ) {
137+ const propNames = {
138+ open: ' show' , minimized: ' minimize' , mobileOpen: ' mobileShow'
139+ }
140+ this .$emit (` update:${ propNames[variable]} ` , ! this [variable])
141+ this [variable] = ! this [variable]
64142 }
65143 }
66144}
0 commit comments