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'
112import { createPortal } from 'react-dom'
123import PropTypes from 'prop-types'
134import classNames from 'classnames'
145
15- import { Breakpoints } from '../Types'
166import { useForkedRef } from '../../utils/hooks'
177import { CBackdrop } from '../backdrop/CBackdrop'
188
@@ -26,13 +16,9 @@ export interface CSidebarProps extends HTMLAttributes<HTMLDivElement> {
2616 */
2717 narrow ?: boolean
2818 /**
29- * Method called before the hide animation has started . [docs]
19+ * Event emitted after visibility of component changed . [docs]
3020 */
31- onHide ?: ( ) => void
32- /**
33- * Method called before the show animation has started. [docs]
34- */
35- onShow ?: ( ) => void
21+ onVisibleChange ?: ( visible : boolean ) => void
3622 /**
3723 * Set sidebar to narrow variant. [docs]
3824 */
@@ -41,10 +27,6 @@ export interface CSidebarProps extends HTMLAttributes<HTMLDivElement> {
4127 * Place sidebar in non-static positions. [docs]
4228 */
4329 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
4830 /**
4931 * Size the component small, large, or extra large. [docs]
5032 */
@@ -59,17 +41,28 @@ export interface CSidebarProps extends HTMLAttributes<HTMLDivElement> {
5941 visible ?: boolean
6042}
6143
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+
6257export const CSidebar = forwardRef < HTMLDivElement , CSidebarProps > (
6358 (
6459 {
6560 children,
6661 className,
6762 narrow,
68- onHide,
69- onShow,
63+ onVisibleChange,
7064 overlaid,
7165 position,
72- selfHiding,
7366 size,
7467 unfoldable,
7568 visible,
@@ -81,43 +74,54 @@ export const CSidebar = forwardRef<HTMLDivElement, CSidebarProps>(
8174 const forkedRef = useForkedRef ( ref , sidebarRef )
8275 const [ mobile , setMobile ] = useState ( false )
8376 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 > ( )
9378
9479 useEffect ( ( ) => {
80+ sidebarRef . current && setMobile ( isOnMobile ( sidebarRef . current ) )
81+
9582 setVisible ( visible )
96- setMobile ( isOnMobile ( sidebarRef ) )
9783 } , [ visible ] )
9884
9985 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 ] )
10392
10493 useEffect ( ( ) => {
94+ sidebarRef . current && setMobile ( isOnMobile ( sidebarRef . current ) )
95+ sidebarRef . current && setInViewport ( isVisible ( sidebarRef . current ) )
96+
97+ window . addEventListener ( 'resize' , ( ) => handleResize ( ) )
10598 window . addEventListener ( 'mouseup' , handleClickOutside )
106- sidebarRef . current && sidebarRef . current . addEventListener ( 'mouseup' , handleOnClick )
10799 window . addEventListener ( 'keyup' , handleKeyup )
108100
101+ sidebarRef . current ?. addEventListener ( 'mouseup' , handleOnClick )
102+ sidebarRef . current ?. addEventListener ( 'transitionend' , ( ) => {
103+ sidebarRef . current && setInViewport ( isVisible ( sidebarRef . current ) )
104+ } )
105+
109106 return ( ) => {
107+ window . removeEventListener ( 'resize' , ( ) => handleResize ( ) )
110108 window . removeEventListener ( 'mouseup' , handleClickOutside )
111- sidebarRef . current && sidebarRef . current . removeEventListener ( 'mouseup' , handleOnClick )
112109 window . removeEventListener ( 'keyup' , handleKeyup )
110+
111+ sidebarRef . current ?. removeEventListener ( 'mouseup' , handleOnClick )
112+ sidebarRef . current ?. removeEventListener ( 'transitionend' , ( ) => {
113+ sidebarRef . current && setInViewport ( isVisible ( sidebarRef . current ) )
114+ } )
113115 }
114116 } )
115117
116118 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 ) )
121125 }
122126
123127 const handleKeyup = ( event : Event ) => {
@@ -154,11 +158,10 @@ export const CSidebar = forwardRef<HTMLDivElement, CSidebarProps>(
154158 'sidebar-narrow' : narrow ,
155159 'sidebar-overlaid' : overlaid ,
156160 [ `sidebar-${ position } ` ] : position ,
157- [ `sidebar-self-hiding${ typeof selfHiding !== 'boolean' && '-' + selfHiding } ` ] : selfHiding ,
158161 [ `sidebar-${ size } ` ] : size ,
159162 'sidebar-narrow-unfoldable' : unfoldable ,
160- show : _visible === true ,
161- hide : _visible === false ,
163+ show : _visible === true && mobile ,
164+ hide : _visible === false && ! mobile ,
162165 } ,
163166 className ,
164167 )
@@ -183,14 +186,9 @@ CSidebar.propTypes = {
183186 children : PropTypes . node ,
184187 className : PropTypes . string ,
185188 narrow : PropTypes . bool ,
186- onHide : PropTypes . func ,
187- onShow : PropTypes . func ,
189+ onVisibleChange : PropTypes . func ,
188190 overlaid : PropTypes . bool ,
189191 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- ] ) ,
194192 size : PropTypes . oneOf ( [ 'sm' , 'lg' , 'xl' ] ) ,
195193 unfoldable : PropTypes . bool ,
196194 visible : PropTypes . bool ,
0 commit comments