ModalPredefined
@cloud-ru/ds-uikit-product-modal-predefined — Product preset-компоненты для delete, recall и release notes сценариев на базе Modal и BottomSheet.
Пакет @cloud-ru/ds-uikit-product-modal-predefined предоставляет готовые product-сценарии поверх @cloud-ru/ds-modal и @cloud-ru/ds-bottom-sheet.
- DeleteModal — удаление объекта с опциональным подтверждением через ввод текста.
- RecallModal — отзыв действия с тем же подтверждением через ввод текста.
- ReleaseNotes — адаптивный release notes: модальное окно на desktop, bottom sheet на mobile; состояния
data,noData,error.
Установка
pnpm add @cloud-ru/ds-uikit-product-modal-predefined
import { DeleteModal, RecallModal, ReleaseNotes } from '@cloud-ru/ds-uikit-product-modal-predefined'
Figma
Источник: Product UI Kit (variables), root node 3179:1987.
Пакет следует Figma-first API: contentState — публичная визуальная ось, поле подтверждения включается пропом confirmText. Legacy @cloud-ru/uikit-product-modal-predefined используется как источник поведения, но новый пакет не является drop-in заменой legacy API.
DeleteModal
Готовое модальное окно удаления с опциональным подтверждением через ввод текста.
DeleteModal — готовый сценарий удаления объекта. Вариант из макета deleteModalConfirmable включается пропом confirmText: если он передан, модалка показывает поле подтверждения.
Примеры использования
Базовое удаление
import { Button } from '@cloud-ru/ds-button';
import { DeleteModal } from '@cloud-ru/ds-uikit-product-modal-predefined';
import { useState } from 'react';
export function DeleteBasic() {
const [open, setOpen] = useState(false);
return (
<>
<Button label='Open delete modal' view='filled' appearance='primary' onClick={() => setOpen(true)} />
<DeleteModal
open={open}
onClose={() => setOpen(false)}
objectType='виртуальную машину'
onDelete={close => close()}
/>
</>
);
}
Удаление с подтверждением
import { Button } from '@cloud-ru/ds-button';
import { DeleteModal } from '@cloud-ru/ds-uikit-product-modal-predefined';
import { useState } from 'react';
export function DeleteConfirmable() {
const [open, setOpen] = useState(false);
return (
<>
<Button label='Open confirmable delete modal' view='filled' appearance='primary' onClick={() => setOpen(true)} />
<DeleteModal
open={open}
onClose={() => setOpen(false)}
objectType='виртуальную машину'
confirmText='vm-production-01'
onDelete={close => close()}
/>
</>
);
}
Props
DeleteModalProps
| Prop | Type | Default | Description |
|---|---|---|---|
closeOnPopstate | boolean | — | Закрытие при навигации по истории |
confirmText | string | — | Текст, который нужно ввести для подтверждения. Если передан — модалка показывает поле подтверждения |
confirmTextVariant | "name" | "text" | name | Тип текста подтверждения |
content | ReactNode | — | Основной текст модалки |
data-test-id | string | — | |
deleting | boolean | — | Состояние загрузки кнопки удаления |
hideConfirmCopyButton | boolean | — | Скрыть кнопку копирования текста подтверждения |
mode | "aggressive" | "forced" | "regular" | MODE.Regular | Режим закрытия: Regular — overlay/Esc/кнопка; Aggressive — только кнопка; Forced — без кнопки и overlay/Esc. |
objectType | string | — | Тип удаляемого объекта, отображается в заголовке |
onClose | () => void | — | Колбэк закрытия |
onDelete | (onClose: () => void) => void | — | Колбэк подтверждения удаления |
open | boolean | — | Управление состоянием показан/не показан |
subtitle | ReactNode | — | Подзаголовок |
titleTooltip | ReactNode | — | Подсказка рядом с заголовком |
Related types
ConfirmTextVariant="name"|"text"
RecallModal
Готовое модальное окно отзыва действия с опциональным подтверждением через ввод текста.
RecallModal — готовый сценарий отзыва действия. Вариант из макета recallModalConfirmable включается пропом confirmText: если он передан, модалка показывает поле подтверждения.
Примеры использования
Базовый отзыв
import { Button } from '@cloud-ru/ds-button';
import { RecallModal } from '@cloud-ru/ds-uikit-product-modal-predefined';
import { useState } from 'react';
export function RecallBasic() {
const [open, setOpen] = useState(false);
return (
<>
<Button label='Open recall modal' view='filled' appearance='primary' onClick={() => setOpen(true)} />
<RecallModal open={open} onClose={() => setOpen(false)} onRecall={close => close()} />
</>
);
}
Отзыв с подтверждением
import { Button } from '@cloud-ru/ds-button';
import { RecallModal } from '@cloud-ru/ds-uikit-product-modal-predefined';
import { useState } from 'react';
export function RecallConfirmable() {
const [open, setOpen] = useState(false);
return (
<>
<Button label='Open confirmable recall modal' view='filled' appearance='primary' onClick={() => setOpen(true)} />
<RecallModal
open={open}
onClose={() => setOpen(false)}
confirmText='recall-operation-01'
onRecall={close => close()}
/>
</>
);
}
Props
RecallModalProps
| Prop | Type | Default | Description |
|---|---|---|---|
closeOnPopstate | boolean | — | Закрытие при навигации по истории |
confirmText | string | — | Текст, который нужно ввести для подтверждения. Если передан — модалка показывает поле подтверждения |
content | ReactNode | — | Основной текст модалки |
data-test-id | string | — | |
hideConfirmCopyButton | boolean | — | Скрыть кнопку копирования текста подтверждения |
loading | boolean | — | Состояние загрузки кнопки отзыва |
mode | "aggressive" | "forced" | "regular" | MODE.Regular | Режим закрытия: Regular — overlay/Esc/кнопка; Aggressive — только кнопка; Forced — без кнопки и overlay/Esc. |
onClose | () => void | — | Колбэк закрытия |
onRecall | (onClose: () => void) => void | — | Колбэк подтверждения отзыва |
open | boolean | — | Управление состоянием показан/не показан |
subtitle | ReactNode | — | Подзаголовок |
titleTooltip | ReactNode | — | Подсказка рядом с заголовком |
ReleaseNotes
Адаптивный release notes preset — модальное окно на desktop, bottom sheet на mobile.
ReleaseNotes — адаптивный preset для показа новостей платформы. На desktop это модальное окно, на mobile — bottom sheet; поверхность выбирается автоматически по раскладке. Публичная визуальная ось contentState принимает data, noData, error.
Примеры использования
Данные
import { Button } from '@cloud-ru/ds-button';
import { ReleaseNotes } from '@cloud-ru/ds-uikit-product-modal-predefined';
import { useState } from 'react';
import { releaseNotesItems } from './releaseNotesItems';
export function ReleaseNotesData() {
const [open, setOpen] = useState(false);
return (
<>
<Button label='Open release notes' view='filled' appearance='primary' onClick={() => setOpen(true)} />
<ReleaseNotes open={open} onClose={() => setOpen(false)} items={releaseNotesItems} />
</>
);
}
Нет данных
import { Button } from '@cloud-ru/ds-button';
import { ReleaseNotes } from '@cloud-ru/ds-uikit-product-modal-predefined';
import { useState } from 'react';
import { releaseNotesItems } from './releaseNotesItems';
export function ReleaseNotesNoData() {
const [open, setOpen] = useState(false);
return (
<>
<Button label='Open no-data release notes' view='filled' appearance='primary' onClick={() => setOpen(true)} />
<ReleaseNotes open={open} onClose={() => setOpen(false)} contentState='noData' items={releaseNotesItems} />
</>
);
}
Ошибка загрузки
import { Button } from '@cloud-ru/ds-button';
import { ReleaseNotes } from '@cloud-ru/ds-uikit-product-modal-predefined';
import { useState } from 'react';
import { releaseNotesItems } from './releaseNotesItems';
export function ReleaseNotesError() {
const [open, setOpen] = useState(false);
return (
<>
<Button label='Open error release notes' view='filled' appearance='primary' onClick={() => setOpen(true)} />
<ReleaseNotes
open={open}
onClose={() => setOpen(false)}
contentState='error'
items={releaseNotesItems}
onDataErrorRetryClick={() => undefined}
/>
</>
);
}
Видео в новости
import { Button } from '@cloud-ru/ds-button';
import { ReleaseNotes } from '@cloud-ru/ds-uikit-product-modal-predefined';
import { useState } from 'react';
import { releaseNotesItems } from './releaseNotesItems';
export function ReleaseNotesVideo() {
const [open, setOpen] = useState(false);
return (
<>
<Button label='Open video release notes' view='filled' appearance='primary' onClick={() => setOpen(true)} />
<ReleaseNotes
open={open}
onClose={() => setOpen(false)}
items={[
{
...releaseNotesItems[0],
video: 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4',
},
]}
/>
</>
);
}
Props
ReleaseNotesProps
| Prop | Type | Default | Description |
|---|---|---|---|
closeOnPopstate | boolean | — | Закрытие при навигации по истории |
contentState | "data" | "error" | "noData" | — | Визуальное состояние контента по Figma |
data-test-id | string | — | |
items | NoteItemProps | — | Массив новостей |
loading | boolean | — | Состояние загрузки контента |
onClose | () => void | — | Колбэк закрытия |
onDataErrorRetryClick | (() => void) | — | Действие перезагрузки на экране ошибки |
onReadLaterClick | (() => void) | — | Действие "Ознакомиться позже" |
onSlideChange | ((slide: number) => void) | — | Действие при смене слайда |
open | boolean | — | Управление состоянием показан/не показан |
readLaterButtonProps | ButtonProps | — | Только mobile: дополнительные пропсы action-кнопки "Ознакомиться позже" (на desktop игнорируется). |
snapPoint | SnapPoint | 0.85 | Только mobile: фиксированная позиция bottom sheet по высоте (на desktop игнорируется). Доля вьюпорта, пиксели или viewport-единицы — см. SnapPoint из @cloud-ru/ds-bottom-sheet. |
Related types
NoteItemProps
| Prop | Type | Default | Description |
|---|---|---|---|
description | string | — | Описание новости в markdown |
image | { src: string; alt: string; } | — | Иллюстрация |
title | string | — | Заголовок новости |
video | string | undefined | — | Видео вместо статичной иллюстрации |
ReleaseNotesContentState="data"|"error"|"noData"
Размеры и иллюстрации
На desktop карточка новости — квадрат 380×380: иллюстрация занимает правую половину целиком, текст — остаток ширины. Размер карточки фиксирован, поэтому окно одного размера во всех состояниях и не зависит ни от длины описания, ни от того, загрузились ли данные; описание, которое не помещается, прокручивается внутри карточки. На mobile карточка растёт по контенту, а прокручивается тело sheet'а целиком — размер держит сам sheet. Его позицию задаёт проп snapPoint — доля вьюпорта, пиксели или viewport-единицы; по умолчанию 1, весь экран.
Размеры медиа-слота задаёт раскладка, а не сам файл: на desktop это те же 380×380, на mobile — квадрат во всю ширину карточки. До загрузки слот занят скелетоном, при ошибке загрузки — заглушкой с иконкой. Изображение вписывается по object-fit: cover: всё, что выходит за границы слота, обрезается — оставляйте в иллюстрации запас по краям.
Адаптивность
ReleaseNotes — адаптивный компонент с переключением поверхности (surface-swap). Раскладку он берёт из AdaptiveProvider (контекст @cloud-ru/ds-adaptive); публичный API единый для обеих платформ:
- desktop (по умолчанию) — модальное окно (
ModalCustomиз@cloud-ru/ds-modal) с каруселью новостей и постраничной навигацией. - mobile — контент рендерится в
BottomSheetиз@cloud-ru/ds-bottom-sheet(панель снизу со свайпом для закрытия).
Верстайте под desktop и поставьте один <AdaptiveProvider> в корне приложения — mobile-поверхность включается автоматически (desktop-first). Пропа layoutType у компонента нет: источник раскладки — только контекст.
Как форсировать платформу
Форс — только контекстом, не пропом:
- Поддерево — вложенный провайдер:
import { AdaptiveProvider } from '@cloud-ru/ds-adaptive' <AdaptiveProvider layoutType='mobile'> <ReleaseNotes open={open} onClose={close} items={items} /> </AdaptiveProvider> - Отдельный компонент —
withLayoutType(module-scope, сахар над провайдером):import { withLayoutType } from '@cloud-ru/ds-adaptive' import { ReleaseNotes } from '@cloud-ru/ds-uikit-product-modal-predefined' const MobileReleaseNotes = withLayoutType(ReleaseNotes, 'mobile')
Платформенные пропы
Таблица синхронизирована с type-level JSDoc у ReleaseNotesProps.
| Пропы | desktop | mobile |
|---|---|---|
readLaterButtonProps, snapPoint | игнорируются | используются |
open, onClose, container, closeOnPopstate, contentState, items, loading, onReadLaterClick, onDataErrorRetryClick, onSlideChange | используется | используется |
Подробнее о модели адаптивности — Adaptive.