Skip to content

Commit 10f3036

Browse files
committed
refactor(CSidebar): update responsive behavior
1 parent a73f626 commit 10f3036

File tree

1 file changed

+50
-52
lines changed

1 file changed

+50
-52
lines changed

src/components/sidebar/CSidebar.tsx

Lines changed: 50 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,8 @@
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'
112
import { createPortal } from 'react-dom'
123
import PropTypes from 'prop-types'
134
import classNames from 'classnames'
145

15-
import { Breakpoints } from '../Types'
166
import { useForkedRef } from '../../utils/hooks'
177
import { 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+
6257
export 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

Comments
 (0)