Skip to content

Commit

Permalink
Merge pull request #1289 from core-ds/feat/bottom-sheet-native-keyboard
Browse files Browse the repository at this point in the history
feat(bottom-sheet): added virtual keyboard support
  • Loading branch information
hextion authored Jul 16, 2024
2 parents 5598dd4 + 7bc80e0 commit 2783782
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/ten-roses-smell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@alfalab/core-components-bottom-sheet': minor
---

Добавлен проп для случаев, когда необходима отзывчивость компонента из-за изменении видимой части браузера при открытии клавиатуры устройства
15 changes: 12 additions & 3 deletions packages/bottom-sheet/src/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { Header, HeaderProps } from './components/header/Component';
import { SwipeableBackdrop } from './components/swipeable-backdrop/Component';
import { horizontalDirections } from './consts/swipeConsts';
import { ShouldSkipSwipingParams } from './types/swipeTypes';
import { useVisibleViewportSize } from './hooks';
import type { BottomSheetProps } from './types';
import {
CLOSE_OFFSET,
Expand Down Expand Up @@ -103,10 +104,14 @@ export const BottomSheet = forwardRef<HTMLDivElement, BottomSheetProps>(
swipeableMarkerClassName,
backButtonProps,
iOSLock = false,
virtualKeyboard = false,
},
ref,
) => {
const fullHeight = use100vh() || 0;
const windowHeight = use100vh() ?? 0;
const visibleViewportSize = useVisibleViewportSize(virtualKeyboard);
const fullHeight = virtualKeyboard ? visibleViewportSize?.height ?? 0 : windowHeight;

// Хук use100vh рассчитывает высоту вьюпорта в useEffect, поэтому на первый рендер всегда возвращает null.
const isFirstRender = fullHeight === 0;

Expand All @@ -123,10 +128,10 @@ export const BottomSheet = forwardRef<HTMLDivElement, BottomSheetProps>(
? document?.documentElement?.clientHeight || window?.innerHeight
: 0;

const viewHeight = os.isIOS() ? iOSViewHeight : fullHeight;
const viewHeight = os.isIOS() && !virtualKeyboard ? iOSViewHeight : fullHeight;

return [0, viewHeight - headerOffset];
}, [fullHeight, headerOffset, magneticAreasProp]);
}, [fullHeight, headerOffset, magneticAreasProp, virtualKeyboard]);

const lastMagneticArea = magneticAreas[magneticAreas.length - 1];

Expand Down Expand Up @@ -544,6 +549,10 @@ export const BottomSheet = forwardRef<HTMLDivElement, BottomSheetProps>(
? `${lastMagneticArea}px`
: 'unset',
maxHeight: isFirstRender ? 0 : `${lastMagneticArea}px`,
marginBottom:
virtualKeyboard && visibleViewportSize && windowHeight > visibleViewportSize.height
? windowHeight - visibleViewportSize.height - visibleViewportSize.offsetTop
: undefined,
});

const renderMarker = () => {
Expand Down
1 change: 1 addition & 0 deletions packages/bottom-sheet/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { useVisibleViewportSize } from './use-visualviewport-size';
39 changes: 39 additions & 0 deletions packages/bottom-sheet/src/hooks/use-visualviewport-size.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useEffect, useState } from 'react';

import { fnUtils, isClient } from '@alfalab/core-components-shared';

type VisualViewportSize = Pick<VisualViewport, 'height' | 'offsetTop'>;

const measureVisualViewport = (
visualViewport: VisualViewport | null,
): VisualViewportSize | null => {
if (!visualViewport) return null;
const { height, offsetTop } = visualViewport;

return { height, offsetTop };
};

export function useVisibleViewportSize(enabled = false): VisualViewportSize | null {
const [size, setSize] = useState<Pick<VisualViewport, 'height' | 'offsetTop'> | null>(() =>
isClient() ? measureVisualViewport(window.visualViewport) : null,
);

useEffect(() => {
const { visualViewport } = window;

if (!isClient() || !enabled || !visualViewport) return fnUtils.noop;

const listener = (event: Event) =>
setSize(measureVisualViewport(event.target as VisualViewport));

visualViewport.addEventListener('resize', listener);
visualViewport.addEventListener('scroll', listener);

return () => {
visualViewport.removeEventListener('resize', listener);
visualViewport.removeEventListener('scroll', listener);
};
}, [enabled]);

return size;
}
5 changes: 5 additions & 0 deletions packages/bottom-sheet/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,4 +347,9 @@ export type BottomSheetProps = {
* Блокирует скролл когда модальное окно открыто. Работает только на iOS
*/
iOSLock?: boolean;

/**
* Учитывать высоту виртуальной клавиатуры
*/
virtualKeyboard?: boolean;
};

0 comments on commit 2783782

Please sign in to comment.