Skip to content

Commit d30edf5

Browse files
author
Hector Arce De Las Heras
committed
Refactor device height handling with new useDeviceHeight hook
This commit introduces a significant refactoring of the application's handling of device height. A new hook, useDeviceHeight, has been introduced and is now used across multiple components to set the height. The previous viewportHeight mixin has been removed and replaced with a CSS variable --100svh that is set by the new hook. This refactoring aims to enhance the application's responsiveness to changes in device height. Components such as ActionBottomSheet and Drawer have been updated to use the new hook and CSS variable. Tests for the new useDeviceHeight hook have also been added.
1 parent 2bd35c0 commit d30edf5

File tree

10 files changed

+108
-9
lines changed

10 files changed

+108
-9
lines changed

src/components/actionBottomSheet/actionBottomSheet.styled.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ type IActionBottomSheetStyles = {
1313
styles?: CommonStyleType;
1414
};
1515

16-
export const ActionBottomSheetSyled = styled.div<IActionBottomSheetStyles & { $height?: string }>`
16+
export const ActionBottomSheetStyled = styled.div<IActionBottomSheetStyles & { $height?: string }>`
1717
max-height: 100vh;
18+
max-height: var(--100svh, 100vh);
19+
max-height: 100svh;
1820
${props => getStyles(props.styles)}
1921
height: ${({ $height }) => $height};
2022
`;
@@ -49,6 +51,8 @@ export const ActionBottomSheetContentStyled = styled.div<IActionBottomSheetStyle
4951
${({ theme: { MEDIA_QUERIES } }) => css`
5052
${MEDIA_QUERIES?.mobileAndTablet} {
5153
max-height: 100vh;
54+
max-height: var(--100svh, 100vh);
55+
max-height: 100svh;
5256
}
5357
`}
5458
`;

src/components/actionBottomSheet/actionBottomSheetControlled.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as React from 'react';
22

33
import { PopoverControlled as Popover } from '@/components/popover';
44
import { STYLES_NAME } from '@/constants';
5-
import { useId, useMediaDevice, useScrollEffect } from '@/hooks';
5+
import { useDeviceHeight, useId, useMediaDevice, useScrollEffect } from '@/hooks';
66
import { useStyles } from '@/hooks/useStyles/useStyles';
77
import { ErrorBoundary, FallbackComponent } from '@/provider/errorBoundary';
88
import { DeviceBreakpointsType } from '@/types';
@@ -22,6 +22,7 @@ const ActionBottomSheetControlledStructureComponent = React.forwardRef(
2222
{ variant, ctv, ...props }: IActionBottomSheetControlledStructure<V>,
2323
ref: React.ForwardedRef<HTMLDivElement> | undefined | null
2424
): JSX.Element => {
25+
useDeviceHeight();
2526
const styles = useStyles<ActionBottomSheetVariantStylesType, V>(
2627
STYLES_NAME.ACTION_BOTTOM_SHEET,
2728
variant,

src/components/actionBottomSheet/actionBottomSheetStandAlone.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
ActionBottomSheetHeaderContentStyled,
99
ActionBottomSheetHeaderStyled,
1010
ActionBottomSheetIconSyled,
11-
ActionBottomSheetSyled,
11+
ActionBottomSheetStyled,
1212
ActionBottomSheetTitleSyled,
1313
} from './actionBottomSheet.styled';
1414
import { IActionBottomSheetStandAlone } from './types';
@@ -18,7 +18,7 @@ const ActionBottomSheetStandAloneComponent = (
1818
ref: React.ForwardedRef<HTMLDivElement> | undefined | null
1919
): JSX.Element => {
2020
return (
21-
<ActionBottomSheetSyled
21+
<ActionBottomSheetStyled
2222
ref={ref}
2323
$height={props.height}
2424
data-testid={`${props.dataTestId}Container`}
@@ -53,7 +53,7 @@ const ActionBottomSheetStandAloneComponent = (
5353
<ActionBottomSheetContentStyled ref={scrollableRef} styles={props.styles.content}>
5454
{props.children}
5555
</ActionBottomSheetContentStyled>
56-
</ActionBottomSheetSyled>
56+
</ActionBottomSheetStyled>
5757
);
5858
};
5959

src/components/drawer/drawer.styled.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ export const DrawerTitleContentFooterContainerStyled = styled.div<DrawerStylesTy
2323
//Height is 100svh minus DrawerNavigationStyled total height
2424
height: ${props =>
2525
!props.blocked
26-
? `calc(100svh - (${props.styles.iconContainer?.padding_top} + ${props.styles.iconContainer?.padding_right} + ${props.styles.icon?.width}))`
27-
: '100svh'};
26+
? `calc(var(--100svh, 100vh) - (${props.styles.iconContainer?.padding_top} + ${props.styles.iconContainer?.padding_right} + ${props.styles.icon?.width}))`
27+
: 'var(--100svh, 100vh)'};
2828
${props => getStyles(props.styles.titleContentFooterContainer)}
2929
`;
3030

@@ -34,7 +34,9 @@ export const DrawerTitleStyled = styled.div.withConfig({
3434

3535
export const DrawerStyled = styled.div<DrawerStylesType>`
3636
background-color: #fff;
37-
height: 100svh;
37+
max-height: 100vh;
38+
max-height: var(--100svh, 100vh);
39+
max-height: 100svh;
3840
min-width: 50vw;
3941
max-width: 50vw;
4042
overflow-y: auto;
@@ -45,9 +47,13 @@ export const DrawerStyled = styled.div<DrawerStylesType>`
4547
},
4648
}) => css`
4749
${onlyDesktop} {
50+
min-height: 100vh;
51+
min-height: var(--100svh, 100vh);
4852
min-height: 100svh;
4953
}
5054
${onlyTablet} {
55+
min-height: 100vh;
56+
min-height: var(--100svh, 100vh);
5157
min-height: 100svh;
5258
}
5359
`};

src/components/drawer/drawerControlled.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react';
22

33
import { STYLES_NAME } from '@/constants';
4-
import { useMediaDevice, useScrollEffect, useZoomEffect } from '@/hooks';
4+
import { useDeviceHeight, useMediaDevice, useScrollEffect, useZoomEffect } from '@/hooks';
55
import { useStyles } from '@/hooks/useStyles/useStyles';
66
import { ErrorBoundary, FallbackComponent } from '@/provider/errorBoundary';
77
import { CssProperty } from '@/utils';
@@ -28,6 +28,7 @@ const DrawerControlledComponent = React.forwardRef(
2828
{ portalId, ...props }: IDrawerControlled<V>,
2929
ref: React.ForwardedRef<HTMLDivElement> | undefined | null
3030
): JSX.Element => {
31+
useDeviceHeight();
3132
const styles = useStyles<DrawerVariantStylesType, V>(
3233
STYLES_NAME.DRAWER,
3334
props.variant,

src/hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ export * from './useManageState/useManageState';
1616
export { useScrollEffect } from './useScrollEffect/useScrollEffect';
1717
export * from './useScrollPosition/useScrollPosition';
1818
export { useZoomEffect } from './useZoomEffect/useZoomEffect';
19+
export { useDeviceHeight } from './useDeviceHeight/useDeviceHeight';
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { renderHook } from '@testing-library/react-hooks';
2+
3+
import { useDeviceHeight } from '../useDeviceHeight';
4+
5+
jest.useFakeTimers();
6+
7+
describe('useDeviceHeight', () => {
8+
beforeAll(() => {
9+
window.CSS = {
10+
supports: () => true,
11+
} as unknown as typeof CSS;
12+
});
13+
14+
it('should set --100svh property on resize', () => {
15+
const supportsSpy = jest.spyOn(window.CSS, 'supports');
16+
const setPropertySpy = jest.spyOn(document.documentElement.style, 'setProperty');
17+
const addEventListenerSpy = jest.spyOn(window, 'addEventListener');
18+
19+
renderHook(() => useDeviceHeight());
20+
21+
const resizeEvent = new Event('resize');
22+
window.dispatchEvent(resizeEvent);
23+
24+
expect(addEventListenerSpy).toHaveBeenCalledWith('resize', expect.any(Function));
25+
jest.runAllTimers();
26+
expect(setPropertySpy).toHaveBeenCalledWith('--100svh', '100svh');
27+
28+
supportsSpy.mockRestore();
29+
setPropertySpy.mockRestore();
30+
addEventListenerSpy.mockRestore();
31+
});
32+
33+
afterAll(() => {
34+
(window as Window & { CSS: unknown }).CSS = undefined;
35+
});
36+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { useEffect, useRef } from 'react';
2+
3+
export const useDeviceHeight = (): void => {
4+
const timeout = useRef<ReturnType<typeof setTimeout> | null>(null);
5+
6+
const setVh = () => {
7+
let vh;
8+
if (!window.CSS.supports) {
9+
vh = `${window.innerHeight}px`;
10+
} else {
11+
const supportSvh =
12+
window.CSS.supports('height: 100svh') || window.CSS.supports('max-height: 100svh');
13+
vh = supportSvh ? '100svh' : `${window.innerHeight}px`;
14+
}
15+
document.documentElement.style.setProperty('--100svh', vh);
16+
};
17+
18+
const debounceHeight = () => {
19+
if (timeout.current) {
20+
clearTimeout(timeout.current);
21+
}
22+
timeout.current = setTimeout(() => {
23+
setVh();
24+
}, 250);
25+
};
26+
27+
useEffect(() => {
28+
setVh();
29+
window.addEventListener('resize', debounceHeight);
30+
return () => {
31+
window.removeEventListener('resize', debounceHeight);
32+
if (timeout.current) {
33+
clearTimeout(timeout.current);
34+
}
35+
};
36+
}, []);
37+
};

src/styles/mixins/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export * from './overflow.mixin';
22
export * from './srOnly.mixin';
33
export { focusVisibleAlt } from './focusAlt.mixin';
44
export * from './input.mixin';
5+
export { viewportHeight } from './viewportHeight.mixin';
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export const viewportHeight = (): string => {
2+
if (!window.CSS.supports) {
3+
return '100vh';
4+
}
5+
6+
if (!window.CSS.supports('height: 100dvh') || !window.CSS.supports('max-height: 100dvh')) {
7+
const { innerHeight } = window;
8+
return `${innerHeight}px`;
9+
}
10+
11+
return '100dvh';
12+
};

0 commit comments

Comments
 (0)