Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { forwardRef, useMemo } from 'react';

import { RootProps } from '../../engines';
import { useEscKeyDown } from '../../hooks';
import { Overlay } from '../Overlay';
import { IconClose } from '../_Icon';
import { cx } from '../../utils';
Expand Down Expand Up @@ -39,9 +40,12 @@ export const bottomSheetRoot = (Root: RootProps<HTMLDivElement, BottomSheetProps
withOverlay = true,
withBlur = true,
withTransition = true,
closeOnEsc = true,
maxHeight = '66dvh',
zIndex = 1000,
onClose = noop,
onOverlayClick,
onEscKeyDown,
className,
view,
size,
Expand All @@ -63,8 +67,19 @@ export const bottomSheetRoot = (Root: RootProps<HTMLDivElement, BottomSheetProps
hasHandle,
});

useEscKeyDown({ opened, closeOnEsc, onEscKeyDown, onClose });

const panelClassName = cx(classes.panel, withTransition && classes.animated, !opened && classes.closed);

const handleOverlayClick = (event: React.MouseEvent<HTMLDivElement>) => {
if (onOverlayClick) {
onOverlayClick(event);
return;
}

onClose();
};

return (
<Root ref={ref} className={className} view={view} size={size} {...rest}>
{withOverlay && opened && (
Expand All @@ -75,7 +90,7 @@ export const bottomSheetRoot = (Root: RootProps<HTMLDivElement, BottomSheetProps
}
withBlur={withBlur}
isClickable
onOverlayClick={onClose}
onOverlayClick={handleOverlayClick}
/>
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,28 @@ export interface BottomSheetProps extends HTMLAttributes<HTMLDivElement> {
*/
zIndex?: CSSProperties['zIndex'];
/**
* Обработчик закрытия шторки. Вызывается при клике по оверлею, по кнопке закрытия или свайпом вниз.
* Обработчик закрытия шторки. Вызывается по кнопке закрытия или свайпом вниз,
* при клике по оверлею (если не передан onOverlayClick)
* и при нажатии ESC (если не передан onEscKeyDown).
*/
onClose?: () => void;

/**
* Обработчик клика по оверлею (если не передан, используется onClose).
*/
onOverlayClick?: (event: React.MouseEvent<HTMLDivElement>) => void;

/**
* Закрывать шторку при нажатии на ESC.
* @default true
*/
closeOnEsc?: boolean;

/**
* Обработчик нажатия ESC (если не передан, используется onClose).
*/
onEscKeyDown?: (event: KeyboardEvent) => void;

/**
* Вид компонента.
*/
Expand Down
16 changes: 15 additions & 1 deletion packages/plasma-new-hope/src/components/Sheet/Sheet.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { forwardRef, useRef } from 'react';

import { RootProps } from '../../engines';
import { useEscKeyDown } from '../../hooks';
import { Overlay } from '../Overlay';
import { cx } from '../../utils';

Expand Down Expand Up @@ -30,6 +31,9 @@ export const sheetRoot = (Root: RootProps<HTMLDivElement, SheetProps>) =>
opened,
children,
onClose,
onOverlayClick,
onEscKeyDown,
closeOnEsc = true,
hasHandle = true,
handlePlacement,
contentHeader,
Expand All @@ -53,6 +57,7 @@ export const sheetRoot = (Root: RootProps<HTMLDivElement, SheetProps>) =>

useOverflow({ opened });
useSheetSwipe({ contentWrapperRef, contentRef, handleRef, throttleMs, hasScrollEvents, onClose });
useEscKeyDown({ opened, closeOnEsc, onEscKeyDown, onClose });

const hasHeader = Boolean(contentHeader);
const hasFooter = Boolean(contentFooter);
Expand All @@ -63,6 +68,15 @@ export const sheetRoot = (Root: RootProps<HTMLDivElement, SheetProps>) =>
? `var(${tokens.sheetOverlayWithBlurColor})`
: `var(${tokens.sheetOverlayColor})`;

const handleOverlayClick = (event: React.MouseEvent<HTMLDivElement>) => {
if (onOverlayClick) {
onOverlayClick(event);
return;
}

onClose();
};

return (
<Root opened={opened} onClose={onClose} view={view} handlePlacement={handlePlacement} ref={rootRef}>
<StyledContentWrapper
Expand All @@ -89,7 +103,7 @@ export const sheetRoot = (Root: RootProps<HTMLDivElement, SheetProps>) =>
backgroundColorProperty={overlayBackgroundToken}
withBlur={withBlur}
isClickable
onOverlayClick={onClose}
onOverlayClick={handleOverlayClick}
/>
)}
</Root>
Expand Down
20 changes: 19 additions & 1 deletion packages/plasma-new-hope/src/components/Sheet/Sheet.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,28 @@ export interface SheetProps extends HTMLAttributes<HTMLDivElement> {
opened?: boolean;

/**
* Обработчик закрытия шторки. Вызывается при клике по оверлею или смахиванию шторки вниз
* Обработчик закрытия шторки. Вызывается при смахивании шторки вниз,
* при клике по оверлею (если не передан onOverlayClick)
* и при нажатии ESC (если не передан onEscKeyDown).
*/
onClose: () => void;

/**
* Обработчик клика по оверлею (если не передан, используется onClose).
*/
onOverlayClick?: (event: React.MouseEvent<HTMLDivElement>) => void;

/**
* Закрывать шторку при нажатии на ESC.
* @default true
*/
closeOnEsc?: boolean;

/**
* Обработчик нажатия ESC (если не передан, используется onClose).
*/
onEscKeyDown?: (event: KeyboardEvent) => void;

/**
* Слот для контента в заголовке
*/
Expand Down
1 change: 1 addition & 0 deletions packages/plasma-new-hope/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export { useCodeHook } from './useCodeHook';
export { useDisableScroll } from './useDisableScroll';
export { useForkRef } from './useForkRef';
export { useResizeObserver } from './useResizeObserver';
export { useEscKeyDown } from './useEscKeyDown';
52 changes: 52 additions & 0 deletions packages/plasma-new-hope/src/hooks/useEscKeyDown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { useEffect, useRef } from 'react';

const ESCAPE_KEYCODE = 27;
const stack: object[] = [];

export type UseEscKeyDownArgs = {
onClose: () => void;
opened?: boolean;
closeOnEsc?: boolean;
onEscKeyDown?: (event: KeyboardEvent) => void;
};

/**
* Закрывает верхний открытый слой по ESC.
* При нескольких открытых Sheet/BottomSheet реагирует только последний.
* Если у верхнего слоя closeOnEsc=false, ESC ничего не закрывает.
*/
export const useEscKeyDown = ({ opened, closeOnEsc = true, onEscKeyDown, onClose }: UseEscKeyDownArgs) => {
const callbackRef = useRef({ closeOnEsc, onEscKeyDown, onClose });
callbackRef.current = { closeOnEsc, onEscKeyDown, onClose };

useEffect(() => {
if (!opened) {
return undefined;
}

const id = {};
stack.push(id);

const onKeyDown = (event: KeyboardEvent) => {
if (event.keyCode !== ESCAPE_KEYCODE || stack[stack.length - 1] !== id || !callbackRef.current.closeOnEsc) {
return;
}

const { onEscKeyDown: onEsc, onClose: close } = callbackRef.current;

if (onEsc) {
onEsc(event);
return;
}

close();
};

window.addEventListener('keydown', onKeyDown);

return () => {
stack.splice(stack.indexOf(id), 1);
window.removeEventListener('keydown', onKeyDown);
};
}, [opened]);
};
22 changes: 11 additions & 11 deletions utils/api-tests/script.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,50 +13,50 @@ const config = {
libs: [
{
name: '@salutejs/plasma-b2c',
excludeComponents: ['TextField', 'CodeArea'],
excludeComponents: ['TextField', 'CodeArea', 'BottomSheet'],
},
{
name: '@salutejs/plasma-web',
excludeComponents: ['TextField', 'CodeArea'],
excludeComponents: ['TextField', 'CodeArea', 'BottomSheet'],
},
{
name: '@salutejs/plasma-giga',
},
{
name: '@salutejs/sdds-bizcom',
excludeComponents: ['CodeArea'],
excludeComponents: ['CodeArea', 'BottomSheet'],
},
{
name: '@salutejs/sdds-cs',
excludeComponents: ['Select', 'InformationWrapper', 'CodeArea'],
excludeComponents: ['Select', 'InformationWrapper', 'CodeArea', 'BottomSheet'],
},
{
name: '@salutejs/sdds-dfa',
excludeComponents: ['InformationWrapper', 'CodeArea'],
excludeComponents: ['InformationWrapper', 'CodeArea', 'BottomSheet'],
},
{
name: '@salutejs/sdds-finai',
excludeComponents: ['CodeArea'],
excludeComponents: ['CodeArea', 'BottomSheet'],
},
{
name: '@salutejs/sdds-insol',
excludeComponents: ['CodeArea'],
excludeComponents: ['CodeArea', 'BottomSheet'],
},
{
name: '@salutejs/sdds-netology',
excludeComponents: ['CodeArea'],
excludeComponents: ['CodeArea', 'BottomSheet'],
},
{
name: '@salutejs/sdds-platform-ai',
excludeComponents: ['CodeArea'],
excludeComponents: ['CodeArea', 'BottomSheet'],
},
{
name: '@salutejs/sdds-scan',
excludeComponents: ['CodeArea'],
excludeComponents: ['CodeArea', 'Sheet', 'BottomSheet'],
},
{
name: '@salutejs/sdds-serv',
excludeComponents: ['CodeArea'],
excludeComponents: ['CodeArea', 'BottomSheet'],
},
],
includeComponents: [],
Expand Down
Loading
Loading