/
sdds
/
plasma
Обзор
Документация
Войти
/
sdds
/
plasma
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
dev
website/plasma-web-docs/docs/components/ModalBase.mdx
407 строк
15 KB
Dima Shugaev
feat(docs): SSRProvider docs updated
24 апр 2026, 09:14
24 апр 2026, 09:14
65163f3
Код
Авторство
О чём код?
--- id: modalBase title: ModalBase --- import { PropsTable } from '@site/src/components'; # ModalBase Компонент ModalBase во многом схож с PopupBase, добавляет при этом подложку(`overlay`), а также блокирует `scroll` и `focus`. ### Быстрый старт Перед использованием убедитесь, что `PopupBaseProvider` подключен. ```tsx live import React from 'react'; import { surfaceSolid02 } from '@salutejs/plasma-tokens-web'; import { Button, ModalBase, PopupBaseProvider } from '@salutejs/plasma-web'; export function App() { const [isOpenA, setIsOpenA] = React.useState(false); const [isOpenB, setIsOpenB] = React.useState(false); return ( <PopupBaseProvider> <div style={{ height: "300px" }}> <div style={{ display: 'flex', flexDirection: 'column' }}> <Button text="Открыть A" onClick={() => setIsOpenA(true)} /> </div> <ModalBase id="modalA" onClose={() => setIsOpenA(false)} opened={isOpenA} placement="center" offset={[0, 0]} > <div style={{ background: `${surfaceSolid02}`, padding: "1rem" }}> <Button onClick={() => setIsOpenA(false)}>Close</Button> <Button text="Открыть B" onClick={() => setIsOpenB(true)} /> Content </div> <ModalBase id="modalB" onClose={() => setIsOpenB(false)} opened={isOpenB} placement="right" offset={[0, 0]} > <div style={{ background: `${surfaceSolid02}`, padding: "1rem" }}> <Button onClick={() => setIsOpenB(false)}>Close</Button> Content </div> </ModalBase> </ModalBase> </div> </PopupBaseProvider> ); } ``` ## Использование стилизованной обертки Свойство `hasBody` позволяет использовать стилизованный `slot`: с отступами и крестиком для закрытия. ### Пример с Note ```tsx live import React from 'react'; import { IconAttentionCircleFill } from '@salutejs/plasma-icons'; import { ButtonGroup, Button, ModalBase, PopupBaseProvider, Note, H3, Overlay } from '@salutejs/plasma-web'; export function App() { const [isOpenA, setIsOpenA] = React.useState(false); return ( <PopupBaseProvider> <div style={{ height: "300px" }}> <div style={{ display: 'flex', flexDirection: 'column' }}> <Button text="Ознакомиться с информацией" onClick={() => setIsOpenA(true)} /> </div> <ModalBase id="modalA" onClose={() => setIsOpenA(false)} opened={isOpenA} placement="center" offset={[0, 0]} hasBody overlay={<Overlay zIndex="0" backgroundColorProperty="rgba(249, 249, 249, 0.56)" />} > <div style={{ display: 'flex', "flex-direction": "column"}}> <H3 style={{ paddingBottom: '24px', marginRight: "32px"}}>Новый ключ авторизации</H3> <Note title="Текущие данные будут сброшены" text="После обновления, вас будет необходимо передавать новый Authorization Key для получения Access Token" view="warning" size="m" contentBeforeSizing="fixed" contentBefore={<IconAttentionCircleFill size="s" color="inherit" />} /> <ButtonGroup style={{ "justify-content": 'flex-end', paddingTop: '24px' }} isCommonButtonStyles={false} gap="wide"> <Button size="m" view="secondary" text="Отменить" onClick={() => setIsOpenA(false)} /> <Button size="m" view="accent" text="Продолжить" onClick={() => setIsOpenA(false)} /> </ButtonGroup> </div> </ModalBase> </div> </PopupBaseProvider> ); } ``` ### Пример с формой ```tsx live import React from 'react'; import { ButtonGroup, Button, ModalBase, PopupBaseProvider, RadioGroup, Radiobox, H3, Overlay, TextFieldGroup, TextField, Cell, CellTextbox, CellTextboxSubtitle, Link, TextS } from '@salutejs/plasma-web'; export function App() { const [isOpenA, setIsOpenA] = React.useState(false); const TextFieldList = [ { label: 'ИНН', name: 'inn' }, { label: 'КПП', name: 'cpp' }, { label: 'Название организации', optional: true, name: 'orgName' }, { label: 'Телефон', name: 'phoneNumber' }, { label: 'Почта', name: 'email' }, ] return ( <PopupBaseProvider> <div style={{ height: "300px" }}> <div style={{ display: 'flex', flexDirection: 'column' }}> <Button text="Открыть форму договора" onClick={() => setIsOpenA(true)} /> </div> <ModalBase id="main" onClose={() => setIsOpenA(false)} opened={isOpenA} placement="center" offset={[0, 0]} hasBody overlay={<Overlay zIndex="0" backgroundColorProperty="rgba(249, 249, 249, 0.56)" />} > <form style={{ display: 'flex', "flex-direction": "column"}}> <H3 style={{ paddingBottom: '10px', marginRight: "32px"}}>Запрос на заключение договора</H3> <Cell size="m"> <CellTextbox> <CellTextboxSubtitle> Для заключение договора на покупку лицензий укажите ваши реквизиты. Инструкция по заключению договора придёт на указанную почту в течение 1 дня. </CellTextboxSubtitle> <TextS> <Link href="/" target="_blank">Подробнее</Link> </TextS> </CellTextbox> </Cell> <RadioGroup style={{ display: 'flex', gap: "16px", marginTop: "24px", marginBottom: "16px"}} aria-labelledby="radiogroup-title-id"> <Radiobox name="radio-1" size="m" label="Юридическое лицо" defaultChecked /> <Radiobox name="radio-1" size="m" label="Индивидуальный предприниматель" /> </RadioGroup> <TextFieldGroup size="m" orientation="vertical" gap="wide"> {TextFieldList.map((props) => ( <TextField {...props} /> ))} </TextFieldGroup> <ButtonGroup style={{ "justify-content": 'flex-end', paddingTop: '24px' }} isCommonButtonStyles={false} gap="wide"> <Button size="m" view="secondary" text="Отмена" onClick={() => setIsOpenA(false)} /> <Button type="submit" size="m" view="accent" text="Отправить запрос" onClick={() => setIsOpenA(false)} /> </ButtonGroup> </form> </ModalBase> </div> </PopupBaseProvider> ); } ``` ## Подключение анимации Подключение анимации аналогично тому, как это происходит в `PopupBase` - через свойство `withAnimation`(управление через `popupBaseClasses`, `modalBaseClasses`). Для добавления анимации в оверлей необходимо использовать класс `.modal-base-overlay` через переменную `modalBaseClasses.overlay` из пакета. Пример: ```tsx const StyledModal = styled(ModalBase)` && > .${popupBaseClasses.root}, .${modalBaseClasses.overlay} { animation: fadeIn 1s forwards; } &&.${popupBaseClasses.endAnimation} .${popupBaseClasses.root} { animation: fadeOut 1s forwards; } &&.${popupBaseClasses.endAnimation} .${modalBaseClasses.overlay} { animation: fadeOut 1s forwards; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } } `; ``` ## FocusTrapped Свойство `isFocusTrapped` захватывает фокус внутри одного DOM элемента. Когда свойство имеет значение `true`, при нажатии `Tab` или `Shift + Tab` фокус будет перемещаться только внутри модального окна. Если поверх текущего модального окна открывается еще одно модальное окно, то фокус захватывает последнее модальное окно. После закрытия модального окна, фокус может свободно перемещаться. Если установить значение `isFocusTrapped` в false, после открытия модального фокус будет перемещен на первый элемент внутри модального окна. Но при последующей навигации с помощью `Tab` или `Shift + Tab` фокус не будет зациклен внутри модального окна и может покинуть его. ## Draggable Чтобы иметь возможность перетаскивать Modal по экрану нужно включить свойство `draggable`. Пример: ```tsx live import React from 'react'; import { Button, ModalBase, PopupBaseProvider } from '@salutejs/plasma-web'; export function App() { const [isOpen, setIsOpen] = React.useState(false); return ( <PopupBaseProvider> <div style={{height: "200px"}}> <div style={{ display: 'flex', flexDirection: 'column' }}> <Button style={{ marginTop: "1rem", width: "15rem" }} text="Открыть" onClick={() => setIsOpen(true)} /> </div> <ModalBase id="modal" isOpen={isOpen} onClose={() => setIsOpen(false)} placement="center" draggable > <div style={{ background: "lightgray", padding: "1rem", height: '100%', boxSizing: 'border-box', borderRadius: '1rem' }}> <Button onClick={() => setIsOpen(false)}>Close</Button> <>Content</> </div> </ModalBase> </div> </PopupBaseProvider> ); } ``` ## Resizable Чтобы иметь возможность растягивать Popup, нужно настроить свойство `resizable`. Формат следующий: ```tsx /** * Настройка resizable-режима. */ resizable?: { /** * Включение/выключение ресайза. * @default false */ disabled?: boolean; /** * Направления для ресайза. */ directions?: ResizeDirections; /** * Начальный размер окна ресайза. */ defaultSize?: { width?: number; height?: number }; /** * Минимальная ширина ресайза в px. */ minWidth?: number; /** * Минимальная высота ресайза в px. */ minHeight?: number; /** * Максимальная ширина ресайза в px. */ maxWidth?: number; /** * Максимальная высота ресайза в px. */ maxHeight?: number; /** * Кастомные иконки ресайза. */ icons?: { topRight?: ReactNode; bottomRight?: ReactNode; bottomLeft?: ReactNode; topLeft?: ReactNode; }; /** * Размер иконки ресайза. * @default s */ iconSize?: 'xs' | 's' | 'm'; /** * Скрывать ли иконку для ресайза. * @default false */ hiddenIcons?: PopupPlacementMixed[]; }; ``` Пример: ```tsx live import React from 'react'; import { Button, ModalBase, PopupBaseProvider } from '@salutejs/plasma-web'; export function App() { const [isOpen, setIsOpen] = React.useState(false); return ( <PopupBaseProvider> <div style={{height: "200px"}}> <div style={{ display: 'flex', flexDirection: 'column' }}> <Button style={{ marginTop: "1rem", width: "15rem" }} text="Открыть" onClick={() => setIsOpen(true)} /> </div> <ModalBase id="modal" isOpen={isOpen} onClose={() => setIsOpen(false)} placement="center" offset={[0, 0]} resizable > <div style={{ background: "lightgray", padding: "1rem", height: '100%', boxSizing: 'border-box', borderRadius: '1rem' }}> <Button onClick={() => setIsOpen(false)}>Close</Button> <>Content</> </div> </ModalBase> </div> </PopupBaseProvider> ); } ``` ## Props <PropsTable name="ModalBase" />