Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 13 additions & 44 deletions packages/base-modal/src/Component.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { render, cleanup, fireEvent, RenderResult, waitFor } from '@testing-library/react';
import { render, cleanup, fireEvent, RenderResult } from '@testing-library/react';

import { BaseModal, BaseModalProps } from './Component';

Expand Down Expand Up @@ -230,7 +230,7 @@ describe('BaseModal', () => {
});

describe('two modal at the same time', () => {
it('should open and close with legacy scroll lock', async () => {
it('should not set overflow hidden by default', () => {
const TestCase = (props?: Partial<BaseModalProps>) => {
const defaultProps = { open: false, ...props };
return (
Expand All @@ -248,11 +248,9 @@ describe('BaseModal', () => {
const { rerender } = render(<TestCase open={false} />);
expect(document.body.style.overflow).toBe('');
rerender(<TestCase open={true} />);
expect(document.body.style.overflow).toBe('hidden');
expect(document.body.style.overflow).toBe('');
rerender(<TestCase open={false} />);
await waitFor(() => {
expect(document.body.style.overflow).toBe('');
});
expect(document.body.style.overflow).toBe('');
});

it('should not set overflow hidden when scrollLock is true', async () => {
Expand Down Expand Up @@ -305,48 +303,19 @@ describe('BaseModal', () => {
expect(container2).toContainElement(getByTestId('BaseModal'));
});

describe('Body styles restore (legacy scrollLock={false})', () => {
it('should restore styles after close', async () => {
const { rerender } = render(<BaseModal open={false} />);
expect(document.body.style.overflow).toBe('');

rerender(<BaseModal open={true} />);
expect(document.body.style.overflow).toBe('hidden');

rerender(<BaseModal open={false} />);
await waitFor(() => {
describe('Body styles with scrollLock', () => {
it.each([false, true])(
'should not set overflow hidden directly when scrollLock=%s',
(scrollLock) => {
const { rerender } = render(<BaseModal open={false} scrollLock={scrollLock} />);
expect(document.body.style.overflow).toBe('');
});
});

it('should restore styles after unmount', async () => {
const { rerender, unmount } = render(<BaseModal open={false} />);
expect(document.body.style.overflow).toBe('');

rerender(<BaseModal open={true} />);
expect(document.body.style.overflow).toBe('hidden');

unmount();

await waitFor(() => {
rerender(<BaseModal open={true} scrollLock={scrollLock} />);
expect(document.body.style.overflow).toBe('');
});
});
});

describe('Body styles with scrollLock={true}', () => {
it('should not set overflow hidden directly - react-remove-scroll handles scroll lock', async () => {
const { rerender } = render(<BaseModal open={false} scrollLock={true} />);
expect(document.body.style.overflow).toBe('');

rerender(<BaseModal open={true} scrollLock={true} />);
// react-remove-scroll не устанавливает overflow: hidden напрямую на body
expect(document.body.style.overflow).toBe('');

rerender(<BaseModal open={false} scrollLock={true} />);
await waitFor(() => {
rerender(<BaseModal open={false} scrollLock={scrollLock} />);
expect(document.body.style.overflow).toBe('');
});
});
},
);
});
});
68 changes: 3 additions & 65 deletions packages/base-modal/src/Component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,14 @@ import cn from 'classnames';

import { Backdrop as DefaultBackdrop, type BackdropProps } from '@alfalab/core-components-backdrop';
import { Portal, type PortalProps } from '@alfalab/core-components-portal';
import { getScrollbarSize, isIOS } from '@alfalab/core-components-shared';
import { getScrollbarSize } from '@alfalab/core-components-shared';
import { Stack } from '@alfalab/core-components-stack';
import { stackingOrder } from '@alfalab/core-components-stack-context';

import { lockScroll, syncHeight, unlockScroll } from './helpers/lockScroll';
import {
handleContainer,
hasScrollbar,
isScrolledToBottom,
isScrolledToTop,
restoreContainerStyles,
} from './utils';

import styles from './index.module.css';
Expand Down Expand Up @@ -92,13 +89,6 @@ export type BaseModalProps = {
*/
disableBackdropClick?: boolean;

/**
* Отключает блокировку скролла при открытии модального окна
* @default false
* @deprecated Используйте `scrollLock={true}`.
*/
disableBlockingScroll?: boolean;

/**
* Управляет блокировкой скролла/overscroll фона при открытой модалке.
* @default false
Expand Down Expand Up @@ -215,12 +205,6 @@ export type BaseModalProps = {
*/
contentElementRef?: MutableRefObject<HTMLDivElement | null>;

/**
* Блокирует скролл когда модальное окно открыто. Работает только на iOS.
* @deprecated Используйте `scrollLock={true}`.
*/
iOSLock?: boolean;

/**
* Хэндлер события прокрутки колесиком
*/
Expand Down Expand Up @@ -279,7 +263,6 @@ export const BaseModal = forwardRef<HTMLDivElement, BaseModalProps>(
disableFocusLock = false,
disableEscapeKeyDown = false,
disableRestoreFocus = false,
disableBlockingScroll = false,
scrollLock = false,
keepMounted = false,
className,
Expand All @@ -298,7 +281,6 @@ export const BaseModal = forwardRef<HTMLDivElement, BaseModalProps>(
componentRef = null,
contentElementRef = null,
usePortal = true,
iOSLock = false,
onWheel,
},
ref,
Expand All @@ -315,7 +297,6 @@ export const BaseModal = forwardRef<HTMLDivElement, BaseModalProps>(
const wrapperRef = useRef<HTMLDivElement>(null);
const scrollableNodeRef = useRef<HTMLDivElement | null>(null);
const contentNodeRef = useRef<HTMLDivElement | null>(null);
const restoreContainerStylesRef = useRef<null | (() => void)>(null);
const mouseDownTarget = useRef<HTMLElement>();
const resizeObserverRef = useRef<ResizeObserver>();

Expand All @@ -331,11 +312,6 @@ export const BaseModal = forwardRef<HTMLDivElement, BaseModalProps>(
const isExited = exited || exited === null;
const shouldRender = keepMounted || open || !isExited;

const getContainer = useCallback(
() => (container ? container() : document.body) as HTMLElement,
[container],
);

const addResizeHandle = useCallback(() => {
if (!resizeObserverRef.current) return;

Expand Down Expand Up @@ -380,10 +356,6 @@ export const BaseModal = forwardRef<HTMLDivElement, BaseModalProps>(

const handleClose = useCallback<Required<BaseModalProps>['onClose']>(
(event, reason) => {
if (!scrollLock && iOSLock && isIOS()) {
unlockScroll();
}

if (onClose) {
onClose(event, reason);
}
Expand All @@ -398,7 +370,7 @@ export const BaseModal = forwardRef<HTMLDivElement, BaseModalProps>(

return null;
},
[onBackdropClick, onClose, onEscapeKeyDown, iOSLock, scrollLock],
[onBackdropClick, onClose, onEscapeKeyDown],
);

const handleBackdropMouseDown = (event: MouseEvent<HTMLElement>) => {
Expand Down Expand Up @@ -492,56 +464,22 @@ export const BaseModal = forwardRef<HTMLDivElement, BaseModalProps>(

if (onUnmount) onUnmount();

if (restoreContainerStylesRef.current) {
restoreContainerStylesRef.current();
}
},
[handleScroll, onUnmount, removeResizeHandle, transitionProps],
);

useEffect(() => {
if (open && isExited) {
/*
* При scrollLock={true} блокировка обрабатывается через react-remove-scroll,
* старая логика нужна только для обратной совместимости (deprecated пропсы)
*/
const shouldUseLegacyScrollLock = !scrollLock && !disableBlockingScroll;

if (shouldUseLegacyScrollLock) {
const el = getContainer();

const shouldIOSLock = iOSLock && isIOS();

handleContainer(el, shouldIOSLock);
if (shouldIOSLock) {
syncHeight();
lockScroll();
}

restoreContainerStylesRef.current = () => {
restoreContainerStylesRef.current = null;
restoreContainerStyles(el);
};
}

setExited(false);
}

if (!open) {
unlockScroll();
}
}, [getContainer, open, disableBlockingScroll, scrollLock, isExited, iOSLock]);
}, [open, isExited]);

useEffect(() => {
const ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill;

resizeObserverRef.current = new ResizeObserver(checkToHasScrollBar);

return () => {
if (restoreContainerStylesRef.current) {
restoreContainerStylesRef.current();
}

if (resizeObserverRef.current) {
resizeObserverRef.current.disconnect();
}
Expand Down
21 changes: 1 addition & 20 deletions packages/bottom-sheet/src/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
import { type HandledEvents } from 'react-swipeable/es/types';
import cn from 'classnames';

import { BaseModal, unlockScroll } from '@alfalab/core-components-base-modal';
import { BaseModal } from '@alfalab/core-components-base-modal';
import { fnUtils, getDataTestId, isClient, isIOS } from '@alfalab/core-components-shared';

import { Footer } from './components/footer/Component';
Expand Down Expand Up @@ -91,7 +91,6 @@ export const BottomSheet = forwardRef<HTMLDivElement, BottomSheetProps>(
hideScrollbar,
hideHeader,
disableOverlayClick,
disableBlockingScroll,
scrollLock = true,
disableFocusLock,
children,
Expand Down Expand Up @@ -125,7 +124,6 @@ export const BottomSheet = forwardRef<HTMLDivElement, BottomSheetProps>(
swipeableMarker,
swipeableMarkerClassName,
backButtonProps,
iOSLock = false,
virtualKeyboard = false,
colors = 'default',
preventScrollOnSwipe,
Expand Down Expand Up @@ -286,9 +284,6 @@ export const BottomSheet = forwardRef<HTMLDivElement, BottomSheetProps>(
const nextAreaIdx = getActiveAreaIndex(nextArea);

if (nextArea === 0) {
if (iOSLock) {
unlockScroll();
}
onClose();

return;
Expand Down Expand Up @@ -327,10 +322,6 @@ export const BottomSheet = forwardRef<HTMLDivElement, BottomSheetProps>(
.find((area) => area < activeArea);

if (nextArea === 0) {
if (iOSLock) {
unlockScroll();
}

onClose();

return;
Expand Down Expand Up @@ -365,10 +356,6 @@ export const BottomSheet = forwardRef<HTMLDivElement, BottomSheetProps>(
isSecondArea && canClose && 1 - currentSheetHeight / activeArea > CLOSE_OFFSET;

if (shouldCloseByOffset) {
if (iOSLock) {
unlockScroll();
}

onClose();

return;
Expand All @@ -390,10 +377,6 @@ export const BottomSheet = forwardRef<HTMLDivElement, BottomSheetProps>(
);

if (nearestArea === 0) {
if (iOSLock) {
unlockScroll();
}

onClose();
} else {
const nextOffset = lastMagneticArea - nearestArea;
Expand Down Expand Up @@ -661,7 +644,6 @@ export const BottomSheet = forwardRef<HTMLDivElement, BottomSheetProps>(
wrapperClassName={cn(modalWrapperClassName, {
[styles.disabledPointerEvents]: hideOverlay,
})}
disableBlockingScroll={disableBlockingScroll}
disableFocusLock={disableFocusLock}
transitionProps={{
appear: true,
Expand All @@ -677,7 +659,6 @@ export const BottomSheet = forwardRef<HTMLDivElement, BottomSheetProps>(
disableEscapeKeyDown={disableEscapeKeyDown}
disableRestoreFocus={disableRestoreFocus}
keepMounted={keepMounted}
iOSLock={iOSLock}
scrollLock={scrollLock}
>
<div
Expand Down
12 changes: 0 additions & 12 deletions packages/bottom-sheet/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,12 +256,6 @@ export type BottomSheetProps = {
*/
disableOverlayClick?: boolean;

/**
* Отключает блокировку скролла при открытии модального окна
* @deprecated Используйте `scrollLock={true}`.
*/
disableBlockingScroll?: boolean;

/**
* Управляет блокировкой скролла/overscroll фона при открытой шторке.
* @default true
Expand Down Expand Up @@ -376,12 +370,6 @@ export type BottomSheetProps = {
*/
onSwipeEnd?: (event: HandledEvents | null) => void;

/**
* Блокирует скролл когда модальное окно открыто. Работает только на iOS
* @deprecated Используйте `scrollLock={true}`.
*/
iOSLock?: boolean;

/**
* Учитывать высоту виртуальной клавиатуры
*/
Expand Down
4 changes: 0 additions & 4 deletions packages/modal/src/typings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ export type ModalDesktopProps = BaseModalProps & {
*/
hasCloser?: boolean;

/**
* Блокирует скролл когда модальное окно открыто. Работает только на iOS.
*/
iOSLock?: boolean;
};

export type ModalMobileProps = Omit<ModalDesktopProps, 'size' | 'fixedPosition'>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
exports[`PopupSheet Snapshot tests should match snapshot 1`] = `
{
"asFragment": [Function],
"baseElement": <body
style="padding-right: 0px; overflow: hidden;"
>
"baseElement": <body>
<div />
<div
alfa-portal-container=""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const CenterModal = forwardRef<HTMLDivElement, UniversalModalDesktopProps
margin,
scrollableContainerRef: scrollableContainerRefProp,
onClose,
scrollLock = false,
...restProps
} = props;

Expand All @@ -57,7 +58,7 @@ export const CenterModal = forwardRef<HTMLDivElement, UniversalModalDesktopProps
ref={ref}
componentRef={componentRef}
scrollHandler='content'
disableBlockingScroll={withoutOverlay}
scrollLock={scrollLock}
wrapperClassName={cn(styles.baseModalContainer, {
[styles.wrapperJustifyStart]: verticalAlign === 'top',
[styles.wrapperJustifyCenter]: verticalAlign === 'center',
Expand Down
Loading
Loading