@yandex/ui
Version:
Yandex UI components
114 lines (88 loc) • 9.62 kB
Markdown
# Modal
<a href='https://github.yandex-team.ru/search-interfaces/frontend/tree/master/packages/lego-components/src/Modal' target='_blank'><img src='https://badger.yandex-team.ru/custom/[Исходники]/[Github
][green]/badge.svg' /></a> <a href='https://search.yandex-team.ru/stsearch?text=Modal.ts&facet.queue=ISL&facet.type=bug&facet.status=128' target='_blank'><img src='https://badger.yandex-team.ru/custom/[Известные проблемы]/[Startrek][blue]/badge.svg' /></a>
<!-- description:start -->
Используется для создания всплывающих модальных окон.
<!-- description:end -->
## Пример использования
Использование с нужным набором модификаторов:
```ts
import React from 'react'
import { compose } from '@bem-react/core'
import {
Modal as ModalDesktop,
withThemeNormal,
} from '@yandex-lego/components/Modal/desktop'
import { withZIndex } from '@yandex-lego/components/withZIndex'
// Композиция из различных модификаторов
const Modal = compose(
withThemeNormal,
withZIndex,
)(ModalDesktop)
const App = () => (
<Modal
theme="normal"
onClose={() => this.setState({ visible: false })}
visible={this.state.visible}
zIndexGroupLevel={20}
>
Привет!
</Modal>
)
```
Использование с полным набором модификаторов:
```ts
// src/App.ts
import React from 'react'
import { Modal } from '@yandex-lego/components/Modal/desktop/bundle'
const App = () => (
<Modal
theme="normal"
onClose={() => this.setState({ visible: false })}
visible={this.state.visible}
zIndexGroupLevel={20}
>
Привет!
</Modal>
)
```
## Примеры
### Базовое использование
Чтобы закрыть модальное окно, установите обработчик `onClose`, в котором измените состояние видимости. Данный обработчик вызывается при нажатии на клавишу `esc`, либо при клике за пределами содержимого модального окна.
{{%story::desktop:surface-modal-desktop--playground%}}
### Стилевое оформление
Чтобы изменить стилевое оформление модального окна, установите свойство `theme` в значение `"normal"`. На уровне `desktop` отвечает за анимацию его открытия/закрытия.
## Свойства
<!-- props:start -->
| Свойство | Тип | По умолчанию | Описание |
| --------------------- | ------------------------------------------------------------------------ | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| contentVerticalAlign? | `"top" \| "middle" \| "bottom"` | `'middle'` | Выравнивание контента по вертикали |
| hasAnimation? | `false \| true` | `true` | Добавляет анимацию при открытии модального окна |
| keepMounted? | `false \| true` | `true` | Сохраняет контейнер в DOM после создания |
| className? | `string` | — | Дополнительный класс |
| innerRef? | `(instance: HTMLDivElement) => void \| RefObject<HTMLDivElement>` | — | Ссылка на корневой DOM-элемент компонента |
| zIndex? | `number` | — | Задает слой `z-index` |
| visible? | `false \| true` | — | Делает попап видимым |
| scope? | `RefObject<HTMLElement>` | `document.body` | Ссылка на DOM-элемент, в котором размещается попап<br>Важно, чтобы контейнер имел `position: relative` для корректного позиционирования |
| forceRender? | `false \| true` | — | Вызывает дополнительный рендер после создания |
| onClose? | `(event: KeyboardEvent \| MouseEvent, source: "esc" \| "click") => void` | — | Обработчик, вызываемый после нажатия на клавишу Esc либо мышкой на область вне контейнера |
| onClick? | `(event: MouseEvent<HTMLDivElement, MouseEvent>) => void` | — | Обработчик, вызываемый при срабатывании события click |
<!-- props:end -->
## Примечание
- Функциональность модального окна основана на компоненте `Popup`.
- Позиционирование компонента выполняется только с помощью CSS.
- Анимация открытия реализована только на уровне `desktop`.
- В модальном окне нет зацикливания фокуса.
### Скрытие ползунков страницы при открытии модального окна
У компонента `Modal` отсутствует встроенный механизм скрытия ползунков на странице.
### Проблема с пролистыванием страницы на iOS и Android
Для позиционирования модального окна поверх контента страницы в компоненте `Modal` используется CSS-стиль `position: fixed`.
Его использование в браузерах на iOS и Android устройствах приводит к тому, что при прокрутке содержимого модального окна прокручивается и страница под ним. Это происходит из-за того, что на iOS и Android нельзя убрать прокрутку `<body>`.
Даже если применить `overflow: hidden`, страница все равно будет прокручиваться.
Варианты решения:
1. При открытии модального окна замените `position:fixed; height: <window height>; overflow:hidden` на `<body>`.
**Недостаток:** текущее положение на странице собьется, поэтому его нужно будет запоминать и выставлять заново. При этом страница под модальным окном будет «скакать»: при его открытии она прокрутится в самое верхнее положение, а при закрытии - вернется в предыдущее.
2. Позиционируйте модальное окно с помощью `position: absolute` и сделайте так, чтобы контент модального окна прокручивался вместе со страницей.
**Недостаток:** можно прокрутить модальное окно далеко вниз или вверх и «потерять» его.
3. Предотвратите события `touchmove`, которые вызывают прокрутку не контента попапа, а самой страницы.
**Недостаток:** невозможно отличить события, которые вызывают прокрутку модального окна от событий, которые вызывают прокрутку страницы, т.к. технически они одинаковы.