@cloud-ru/ds-toaster

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

Система всплывающих уведомлений с тремя типами контента и императивным API.

原始使用文档
文档目录19 节
  1. Когда использовать
  2. Анатомия
  3. Type
  4. Position (default из TOASTER_CONTAINER_DEFAULTS[type] )
  5. Limit (default 5 для SystemEvent, 2 для UserAction, 1 для U…
  6. AutoClose (default 5000 для SystemEvent, 2000 для UserActio…
  7. Stacked (default false )
  8. Draggable (default false ) — ⚠️ экспериментально
  9. Overflow fallback (узкий / низкий viewport, кастомный toast…
  10. ContainerId и маршрутизация
  11. Установка
  12. Props
  13. ToasterContainer
  14. Storybook
  15. Stacking · stacked + displayCloseAllButton
  16. Positions · 6 точек якоря
  17. Triggers · вызов из императивного API
  18. UpdateFlow · id + update -семантика
  19. Mobile · кастомный toasterParent + узкий viewport

Toaster

@cloud-ru/ds-toaster — Система всплывающих уведомлений с тремя типами контента и императивным API.

Три типа контента под разные UX-сценарии:

  • ToastSystemEvent — системные события (5 appearance, link, action). Auto-dismiss 5s, поддерживает stack.
  • ToastUserAction — короткий feedback на пользовательское действие (copy, save). Auto-dismiss 2s.
  • ToastUpload — прогресс загрузки файлов (мульти-файл, pause/resume).

Открытие — через императивный singleton toaster:

import { toaster } from '@cloud-ru/ds-toaster'

toaster.systemEvent.success({ title: 'Сохранено' })
toaster.userAction.neutral({ label: 'Скопировано' })
toaster.upload.startOrUpdate({ status: 'loading', files, progress: { current: 0, total: files.length } })

Когда использовать

  • SystemEvent — результаты асинхронных операций, системные события, критические ошибки с action-кнопками.
  • UserAction — короткий ack на локальное действие («скопировано», «сохранено», «удалено»), опционально с link-отменой.
  • Upload — длительная загрузка файлов с прогрессом и контролем pause/resume/cancel.

Когда тосты не нужны:

  • Блокирующее подтверждение действия — используй Modal/Dialog.
  • Постоянная информация в интерфейсе — используй Alert / InfoBlock.
  • Inline-валидация формы — используй встроенный error-state поля.

Анатомия

По умолчанию SystemEvent и Upload рендерятся в одном контейнере (Figma 26297:48316). Upload-карточка прижата к якорю контейнера, SystemEvent-стек — на противоположной стороне, кнопки Expand/Close all посередине. Кнопки управляют только SystemEvent-стеком, Upload не задевается. UserAction живёт отдельным контейнером (другая позиция, pill-стиль).

<>
  {/* shared контейнер для SystemEvent + Upload */}
  <ToasterContainer
    type={TOASTER_TYPE.SystemEvent}
    position='bottom-right'
    stacked
    displayCloseAllButton
    limit={5}
    autoClose={5000}
  />
  {/* UserAction — отдельно */}
  <ToasterContainer type={TOASTER_TYPE.UserAction} />
</>

Если нужны раздельные контейнеры под SystemEvent и Upload — передавай разные containerId явно и шорткатам, и <ToasterContainer/>.

Менеджер тостов синглтонный, мультиплексирует обращения по containerId. Каждый контейнер автономно держит свой стек и таймеры.

Type

Тип контейнера — определяет, какой тостовый компонент он рендерит:

  • systemEvent — стек системных событий (ToastSystemEvent).
  • userAction — pill-feedback (ToastUserAction).
  • upload — карточка загрузки (ToastUpload).

Position (default из TOASTER_CONTAINER_DEFAULTS[type])

Якорь контейнера на экране:

  • SystemEvent поддерживает все 6 положений: top-left, top-center, top-right, bottom-left, bottom-center, bottom-right.
  • UserAction использует только top-center / bottom-center.

Limit (default 5 для SystemEvent, 2 для UserAction, 1 для Upload)

Максимум одновременно видимых тостов в контейнере. При превышении новые тосты прячутся в начало массива (newest), сохраняя front. Передай limit: 0 — ограничение отключается полностью, вся очередь рендерится (актуально, когда у контейнера есть скролл-fallback по высоте).

AutoClose (default 5000 для SystemEvent, 2000 для UserAction, false для Upload)

Дефолтное время автозакрытия (мс) для всех тостов контейнера. Каскад resolve'а: toastOptions.autoClose (per-toast) → <ToasterContainer autoClose> (per-container) → AUTO_CLOSE_TIME[type] (глобальный). Передать false — автозакрытие выключено по умолчанию.

Stacked (default false)

stacked включает deck-режим: в коллапсе виден front-тост (oldest, ближе к якорю контейнера), новые карточки уходят ghost-стопкой. Hover контейнера разворачивает стек и ставит auto-dismiss на паузу.

Draggable (default false) — ⚠️ экспериментально

draggable включает закрытие тоста свайпом мыши или пальцем. Жест активируется после смещения >32px по оси свайпа; до этого порога клики по детям (например, кнопка close внутри тоста) проходят как обычно. Свайп считается «достаточным», если путь ≥50% размера карточки по оси или скорость ≥2.5px/мс (быстрый флик) — тост уезжает за край и закрывается. Иначе карточка возвращается на место CSS-транзишеном.

draggableDirection (x | y) задаёт ось. По умолчанию выводится из position: top-center / bottom-center → y (свайп вверх/вниз), остальные позиции → x (свайп влево/вправо). Во время взаимодействия таймер автозакрытия паузится. На touch-устройствах нативный скролл по поперечной оси сохраняется (touch-action: pan-x / pan-y), поэтому свайп тоста не конфликтует со скроллом страницы.

Под капотом: на время drag'а карточка переключается в position: fixed и резолвится к .toasterRoot (container-type: size создаёт containing block). Это позволяет свайпу физически выйти за пределы внутреннего @cloud-ru/ds-scroll-host'а (его overflow: hidden иначе клипил бы карточку у границы). Конструкция чувствительна: если в DOM-цепочке между .toasterRoot и тостом появляется новый containing block (transform, filter, will-change, contain), координаты разойдутся и карточка приземлится в неверной точке. Перед prod-использованием поведение нужно стабилизировать.

Overflow fallback (узкий / низкий viewport, кастомный toasterParent)

Контейнер уважает размеры родителя:

  • Ширина. .container и .toast зажаты в min(maxWidth, 100cqw - 2*paddingHorizontal) — на широком экране применяется обычная maxWidth из дизайн-токенов, на узком ужимается, оставляя paddingHorizontal от обоих краёв. 100cqw резолвится к ширине .toasterRoot (он = toasterParent через position: absolute; inset: 0; container-type: size), то есть к ширине родителя, а не viewport'а. Дефолт toasterParent = document.body сохраняет старое поведение.
  • Высота. Содержимое контейнера обёрнуто в <Scroll> (@cloud-ru/ds-scroll) с max-height: min(100cqh, 100dvh) - 2*paddingVertical. Когда суммарная высота тостов превышает доступное окно — появляется внутренний кастомный скролл, хвост стека не уезжает за экран. min(cqh, dvh) нужен ради мобильных браузеров, где cqh зачастую резолвится к "small viewport" (статике без учёта адресной строки), а dvh отражает реально видимую область.

Кастомный toasterParent (openToast({ ..., toasterParent })): передавай HTMLElement — helpers.tsx вставит туда <div data-toaster-root> с container-type: size, и все размерные ограничения зарезолвятся к этому боксу. Для свайпа важно, чтобы между data-toaster-root и тостом не появлялся новый containing block (transform / filter и т.п.) — см. блок про drag.

ContainerId и маршрутизация

Дефолтный containerId для типа — toaster-container__<type>. Несколько <ToasterContainer/> одного типа должны получить уникальные containerId; шорткаты toaster.<type>.*({ containerId }) маршрутизируют тосты в нужный.

Установка

Требует react@>=18 и react-dom@>=18 (с react-dom/client) в зависимостях потребителя. Сам пакет их не объявляет — это design choice монорепо.

pnpm add @cloud-ru/ds-toaster
import {
  ToasterContainer,
  ToastSystemEvent,
  ToastUserAction,
  ToastUpload,
  toaster,
  TOASTER_TYPE,
  UploadItem,
} from '@cloud-ru/ds-toaster'

Props

ToasterContainer

ToasterProps

PropTypeDefaultDescription
autoClosenumber | false—Дефолтное время автозакрытия (мс) для всех тостов этого контейнера. Используется,
если в toastOptions.autoClose явно не передано значение. Передать false —
автозакрытие отключено по умолчанию. Если проп не задан — берётся AUTO_CLOSE_TIME[type].
containerIdstring—Идентификатор контейнера — ключ маршрутизации тостов. Вызов
toaster.<type>.open({ containerId }) находит контейнер по этому id и
рендерит тост в нём. Если не задан — используется дефолт
toaster-container__<type> (см. TOASTER_CONTAINER_PREFIX), общий для
всех контейнеров одного type. Задавай явный id, когда на странице
несколько контейнеров одного типа и нужно адресовать конкретный.
data-test-idstring—Override data-test-id корня контейнера. Если не задан — используется
TEST_IDS.toasterContainer. Имеет смысл, если на странице несколько
контейнеров одного типа и e2e-тестам нужно адресовать конкретный.
displayCloseAllButtonboolean—
draggableboolean—
draggableDirection"x" | "y"—
limitnumber—Максимум одновременно видимых тостов в контейнере. По умолчанию — из TOASTER_CONTAINER_DEFAULTS[type].
position"bottom-center" | "bottom-left" | "bottom-right" | "top-center" | "top-left" | "top-right"—
stackedboolean—
type"system-event" | "upload" | "user-action"—
width"auto" | "full"—
  • DraggableDirection = "x" | "y"

  • SystemEventPosition = "bottom-center" | "bottom-left" | "bottom-right" | "top-center" | "top-left" | "top-right"

  • ToasterWidth = "auto" | "full"

Storybook

Playground — все props контейнера через controls:

Stacking · stacked + displayCloseAllButton

Шесть позиций, у каждой свой контейнер с stacked, limit: 5, autoClose: 5000. В углу — сквозной счётчик тостов (повторные клики продолжают нумерацию). Hover на стеке разворачивает deck, кнопки Expand / Close all появляются при ≥ 2 активных тостах.

Positions · 6 точек якоря

Демонстрация всех position для SystemEvent (top-left / top-center / top-right / bottom-left / bottom-center / bottom-right) рядом — наглядно, как меняется flex-направление и slide-in транзишен у каждой.

Triggers · вызов из императивного API

Список кнопок-триггеров под все шорткаты (toaster.systemEvent.success, …neutral, …error, userAction, upload). Удобно для сверки, как кадровые случаи смотрятся бок о бок.

UpdateFlow · id + update-семантика

Длительный сценарий: один и тот же тост проходит через loading → success → error. Демонстрирует контракт toaster.upload.startOrUpdate(...) / возврат id и update.

Mobile · кастомный toasterParent + узкий viewport

Тосты рендерятся внутри телефонной рамки через toasterParent={frameRef.current}. Ширина / высота клампится по cqw / min(cqh, dvh), скролл-fallback по высоте, swipe-to-dismiss (экспериментально). Можно переключать размер экрана (SE / iPhone / Pro Max) и проверять реакцию на узкий контейнер.

版本与发布记录

@cloud-ru/ds-toaster 共发布 83 个版本,首次发布于 2026/08/18;过去 12 个月发布了 83 个版本。

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

关于 @cloud-ru/ds-toaster 的常见问题

@cloud-ru/ds-toaster 是什么?

Система всплывающих уведомлений с тремя типами контента и императивным API.

如何安装 @cloud-ru/ds-toaster?

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

@cloud-ru/ds-toaster 支持 TypeScript 吗?

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

@cloud-ru/ds-toaster 支持 ESM 还是 CommonJS?

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

@cloud-ru/ds-toaster 可以商用吗?

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

@cloud-ru/ds-toaster 的下载量有多少?

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

@cloud-ru/ds-toaster 还在维护吗?

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