1
- // TODO: check if element is visible after toggle
2
-
3
- import React , {
4
- forwardRef ,
5
- HTMLAttributes ,
6
- useEffect ,
7
- useLayoutEffect ,
8
- useRef ,
9
- useState ,
10
- } from 'react'
1
+ import React , { forwardRef , HTMLAttributes , useEffect , useRef , useState } from 'react'
11
2
import { createPortal } from 'react-dom'
12
3
import PropTypes from 'prop-types'
13
4
import classNames from 'classnames'
14
5
15
- import { Breakpoints } from '../Types'
16
6
import { useForkedRef } from '../../utils/hooks'
17
7
import { CBackdrop } from '../backdrop/CBackdrop'
18
8
@@ -26,13 +16,9 @@ export interface CSidebarProps extends HTMLAttributes<HTMLDivElement> {
26
16
*/
27
17
narrow ?: boolean
28
18
/**
29
- * Method called before the hide animation has started . [docs]
19
+ * Event emitted after visibility of component changed . [docs]
30
20
*/
31
- onHide ?: ( ) => void
32
- /**
33
- * Method called before the show animation has started. [docs]
34
- */
35
- onShow ?: ( ) => void
21
+ onVisibleChange ?: ( visible : boolean ) => void
36
22
/**
37
23
* Set sidebar to narrow variant. [docs]
38
24
*/
@@ -41,10 +27,6 @@ export interface CSidebarProps extends HTMLAttributes<HTMLDivElement> {
41
27
* Place sidebar in non-static positions. [docs]
42
28
*/
43
29
position ?: 'fixed' | 'sticky'
44
- /**
45
- * Make any sidebar self hiding across all viewports or pick a maximum breakpoint with which to have a self hiding up to. [docs]
46
- */
47
- selfHiding ?: Breakpoints | boolean
48
30
/**
49
31
* Size the component small, large, or extra large. [docs]
50
32
*/
@@ -59,17 +41,28 @@ export interface CSidebarProps extends HTMLAttributes<HTMLDivElement> {
59
41
visible ?: boolean
60
42
}
61
43
44
+ const isOnMobile = ( element : HTMLDivElement ) =>
45
+ Boolean ( getComputedStyle ( element ) . getPropertyValue ( '--cui-is-mobile' ) )
46
+
47
+ const isVisible = ( element : HTMLDivElement ) => {
48
+ const rect = element . getBoundingClientRect ( )
49
+ return (
50
+ rect . top >= 0 &&
51
+ rect . left >= 0 &&
52
+ rect . bottom <= ( window . innerHeight || document . documentElement . clientHeight ) &&
53
+ rect . right <= ( window . innerWidth || document . documentElement . clientWidth )
54
+ )
55
+ }
56
+
62
57
export const CSidebar = forwardRef < HTMLDivElement , CSidebarProps > (
63
58
(
64
59
{
65
60
children,
66
61
className,
67
62
narrow,
68
- onHide,
69
- onShow,
63
+ onVisibleChange,
70
64
overlaid,
71
65
position,
72
- selfHiding,
73
66
size,
74
67
unfoldable,
75
68
visible,
@@ -81,43 +74,54 @@ export const CSidebar = forwardRef<HTMLDivElement, CSidebarProps>(
81
74
const forkedRef = useForkedRef ( ref , sidebarRef )
82
75
const [ mobile , setMobile ] = useState ( false )
83
76
const [ _visible , setVisible ] = useState ( visible )
84
-
85
- const isOnMobile = ( element : React . RefObject < HTMLDivElement > ) =>
86
- Boolean (
87
- element . current && getComputedStyle ( element . current ) . getPropertyValue ( '--cui-is-mobile' ) ,
88
- )
89
-
90
- useLayoutEffect ( ( ) => {
91
- setMobile ( isOnMobile ( sidebarRef ) )
92
- } )
77
+ const [ inViewport , setInViewport ] = useState < boolean > ( )
93
78
94
79
useEffect ( ( ) => {
80
+ sidebarRef . current && setMobile ( isOnMobile ( sidebarRef . current ) )
81
+
95
82
setVisible ( visible )
96
- setMobile ( isOnMobile ( sidebarRef ) )
97
83
} , [ visible ] )
98
84
99
85
useEffect ( ( ) => {
100
- setMobile ( isOnMobile ( sidebarRef ) )
101
- _visible && onShow && onShow ( )
102
- } , [ _visible ] )
86
+ typeof inViewport !== 'undefined' && onVisibleChange && onVisibleChange ( inViewport )
87
+ } , [ inViewport ] )
88
+
89
+ useEffect ( ( ) => {
90
+ mobile && visible && setVisible ( false )
91
+ } , [ mobile ] )
103
92
104
93
useEffect ( ( ) => {
94
+ sidebarRef . current && setMobile ( isOnMobile ( sidebarRef . current ) )
95
+ sidebarRef . current && setInViewport ( isVisible ( sidebarRef . current ) )
96
+
97
+ window . addEventListener ( 'resize' , ( ) => handleResize ( ) )
105
98
window . addEventListener ( 'mouseup' , handleClickOutside )
106
- sidebarRef . current && sidebarRef . current . addEventListener ( 'mouseup' , handleOnClick )
107
99
window . addEventListener ( 'keyup' , handleKeyup )
108
100
101
+ sidebarRef . current ?. addEventListener ( 'mouseup' , handleOnClick )
102
+ sidebarRef . current ?. addEventListener ( 'transitionend' , ( ) => {
103
+ sidebarRef . current && setInViewport ( isVisible ( sidebarRef . current ) )
104
+ } )
105
+
109
106
return ( ) => {
107
+ window . removeEventListener ( 'resize' , ( ) => handleResize ( ) )
110
108
window . removeEventListener ( 'mouseup' , handleClickOutside )
111
- sidebarRef . current && sidebarRef . current . removeEventListener ( 'mouseup' , handleOnClick )
112
109
window . removeEventListener ( 'keyup' , handleKeyup )
110
+
111
+ sidebarRef . current ?. removeEventListener ( 'mouseup' , handleOnClick )
112
+ sidebarRef . current ?. removeEventListener ( 'transitionend' , ( ) => {
113
+ sidebarRef . current && setInViewport ( isVisible ( sidebarRef . current ) )
114
+ } )
113
115
}
114
116
} )
115
117
116
118
const handleHide = ( ) => {
117
- if ( _visible ) {
118
- setVisible ( false )
119
- onHide && onHide ( )
120
- }
119
+ setVisible ( false )
120
+ }
121
+
122
+ const handleResize = ( ) => {
123
+ sidebarRef . current && setMobile ( isOnMobile ( sidebarRef . current ) )
124
+ sidebarRef . current && setInViewport ( isVisible ( sidebarRef . current ) )
121
125
}
122
126
123
127
const handleKeyup = ( event : Event ) => {
@@ -154,11 +158,10 @@ export const CSidebar = forwardRef<HTMLDivElement, CSidebarProps>(
154
158
'sidebar-narrow' : narrow ,
155
159
'sidebar-overlaid' : overlaid ,
156
160
[ `sidebar-${ position } ` ] : position ,
157
- [ `sidebar-self-hiding${ typeof selfHiding !== 'boolean' && '-' + selfHiding } ` ] : selfHiding ,
158
161
[ `sidebar-${ size } ` ] : size ,
159
162
'sidebar-narrow-unfoldable' : unfoldable ,
160
- show : _visible === true ,
161
- hide : _visible === false ,
163
+ show : _visible === true && mobile ,
164
+ hide : _visible === false && ! mobile ,
162
165
} ,
163
166
className ,
164
167
)
@@ -183,14 +186,9 @@ CSidebar.propTypes = {
183
186
children : PropTypes . node ,
184
187
className : PropTypes . string ,
185
188
narrow : PropTypes . bool ,
186
- onHide : PropTypes . func ,
187
- onShow : PropTypes . func ,
189
+ onVisibleChange : PropTypes . func ,
188
190
overlaid : PropTypes . bool ,
189
191
position : PropTypes . oneOf ( [ 'fixed' , 'sticky' ] ) ,
190
- selfHiding : PropTypes . oneOfType ( [
191
- PropTypes . bool ,
192
- PropTypes . oneOf < 'sm' | 'md' | 'lg' | 'xl' | 'xxl' > ( [ 'sm' , 'md' , 'lg' , 'xl' , 'xxl' ] ) ,
193
- ] ) ,
194
192
size : PropTypes . oneOf ( [ 'sm' , 'lg' , 'xl' ] ) ,
195
193
unfoldable : PropTypes . bool ,
196
194
visible : PropTypes . bool ,
0 commit comments