@cloud-ru/ds-uikit-product-modal-predefined

中文文档
1.1.4发布于 2026/11/11Apache-2.0TypeScriptESM + CJS近 30 天下载 7653

Product preset-компоненты для delete, recall и release notes сценариев на базе Modal и BottomSheet.

原始使用文档
文档目录13 节
  1. Установка
  2. Figma
  3. DeleteModal
  4. Примеры использования
  5. Props
  6. RecallModal
  7. Примеры использования
  8. Props
  9. ReleaseNotes
  10. Примеры использования
  11. Props
  12. Размеры и иллюстрации
  13. Адаптивность

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

PropTypeDefaultDescription
closeOnPopstateboolean—Закрытие при навигации по истории
confirmTextstring—Текст, который нужно ввести для подтверждения. Если передан — модалка показывает поле подтверждения
confirmTextVariant"name" | "text"nameТип текста подтверждения
contentReactNode—Основной текст модалки
data-test-idstring—
deletingboolean—Состояние загрузки кнопки удаления
hideConfirmCopyButtonboolean—Скрыть кнопку копирования текста подтверждения
mode"aggressive" | "forced" | "regular"MODE.RegularРежим закрытия: Regular — overlay/Esc/кнопка; Aggressive — только кнопка; Forced — без кнопки и overlay/Esc.
objectTypestring—Тип удаляемого объекта, отображается в заголовке
onClose() => void—Колбэк закрытия
onDelete(onClose: () => void) => void—Колбэк подтверждения удаления
openboolean—Управление состоянием показан/не показан
subtitleReactNode—Подзаголовок
titleTooltipReactNode—Подсказка рядом с заголовком
  • 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

PropTypeDefaultDescription
closeOnPopstateboolean—Закрытие при навигации по истории
confirmTextstring—Текст, который нужно ввести для подтверждения. Если передан — модалка показывает поле подтверждения
contentReactNode—Основной текст модалки
data-test-idstring—
hideConfirmCopyButtonboolean—Скрыть кнопку копирования текста подтверждения
loadingboolean—Состояние загрузки кнопки отзыва
mode"aggressive" | "forced" | "regular"MODE.RegularРежим закрытия: Regular — overlay/Esc/кнопка; Aggressive — только кнопка; Forced — без кнопки и overlay/Esc.
onClose() => void—Колбэк закрытия
onRecall(onClose: () => void) => void—Колбэк подтверждения отзыва
openboolean—Управление состоянием показан/не показан
subtitleReactNode—Подзаголовок
titleTooltipReactNode—Подсказка рядом с заголовком

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

PropTypeDefaultDescription
closeOnPopstateboolean—Закрытие при навигации по истории
contentState"data" | "error" | "noData"—Визуальное состояние контента по Figma
data-test-idstring—
itemsNoteItemProps—Массив новостей
loadingboolean—Состояние загрузки контента
onClose() => void—Колбэк закрытия
onDataErrorRetryClick(() => void)—Действие перезагрузки на экране ошибки
onReadLaterClick(() => void)—Действие "Ознакомиться позже"
onSlideChange((slide: number) => void)—Действие при смене слайда
openboolean—Управление состоянием показан/не показан
readLaterButtonPropsButtonProps—Только mobile: дополнительные пропсы action-кнопки "Ознакомиться позже" (на desktop игнорируется).
snapPointSnapPoint0.85Только mobile: фиксированная позиция bottom sheet по высоте (на desktop игнорируется).
Доля вьюпорта, пиксели или viewport-единицы — см. SnapPoint из @cloud-ru/ds-bottom-sheet.

NoteItemProps

PropTypeDefaultDescription
descriptionstring—Описание новости в markdown
image{ src: string; alt: string; }—Иллюстрация
titlestring—Заголовок новости
videostring | 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.

Пропыdesktopmobile
readLaterButtonProps, snapPointигнорируютсяиспользуются
open, onClose, container, closeOnPopstate, contentState, items, loading, onReadLaterClick, onDataErrorRetryClick, onSlideChangeиспользуетсяиспользуется

Подробнее о модели адаптивности — Adaptive.

版本与发布记录

@cloud-ru/ds-uikit-product-modal-predefined 共发布 212 个版本,首次发布于 2026/08/18;过去 12 个月发布了 212 个版本。

版本发布日期距今
1.1.4latest2026/11/11今天
1.1.4-preview-e8fe6b56.0preview2026/11/11今天
1.1.4-preview-c0e895ed.02026/11/11今天
1.1.4-preview-90b10112.02026/11/11今天
1.1.4-preview-fd7dd437.02026/11/101 天前
1.1.4-preview-9a75a2a9.02026/11/101 天前

关于 @cloud-ru/ds-uikit-product-modal-predefined 的常见问题

@cloud-ru/ds-uikit-product-modal-predefined 是什么?

Product preset-компоненты для delete, recall и release notes сценариев на базе Modal и BottomSheet.

如何安装 @cloud-ru/ds-uikit-product-modal-predefined?

在项目目录运行 npm install @cloud-ru/ds-uikit-product-modal-predefined,或使用 pnpm add / yarn add / bun add。

@cloud-ru/ds-uikit-product-modal-predefined 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cloud-ru/ds-uikit-product-modal-predefined 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@cloud-ru/ds-uikit-product-modal-predefined 可以商用吗?

@cloud-ru/ds-uikit-product-modal-predefined 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@cloud-ru/ds-uikit-product-modal-predefined 的下载量有多少?

根据 npm 官方下载统计,@cloud-ru/ds-uikit-product-modal-predefined 在 2026/10/10 – 2026/11/08 这 30 天内被下载 7,653 次,日均约 255 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cloud-ru/ds-uikit-product-modal-predefined 还在维护吗?

最新版本 1.1.4 发布于 2026/11/11(今天);至今共发布 212 个版本,其中过去 12 个月发布了 212 个;首次发布于 2026/08/18。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。