Layout
Пакет @cloud-ru/ds-uikit-product-layout — блоки-состояния продуктового экрана поверх @cloud-ru/ds-info-block и @cloud-ru/ds-block:
EmptyBlock— заглушка пустого состояния (иконка, заголовок, описание, опциональный слот действий).NoAccess— экран ограниченного доступа с локализованным сообщением и lock-иконкой.
Демо
EmptyBlock
alignclassNamecontentdata-test-idfootertitle<EmptyBlock title="Title text" content="Body text" icon={"icon":{}} data-test-id="empty-block-demo" />NoAccess
classNamedata-test-idserviceName<NoAccess serviceName="Название сервиса" data-test-id="no-access-demo" />Когда использовать
EmptyBlock:- список, таблица или экран без данных;
- нужна подсказка-действие («создать», «импортировать») через слот
footer.
NoAccess:- у пользователя нет прав на контент;
- текст сообщения берётся из локали и не задаётся вручную.
Анатомия
Оба компонента строятся на @cloud-ru/ds-block + @cloud-ru/ds-info-block: нейтральная подложка, иконка, заголовок, описание. У EmptyBlock опционален слот footer; у NoAccess — опциональный serviceName над блоком и локализованный текст.
Установка
pnpm add @cloud-ru/ds-uikit-product-layout
import { EmptyBlock, NoAccess } from '@cloud-ru/ds-uikit-product-layout';
import '@cloud-ru/ds-uikit-product-layout/style.css';
NoAccess берёт текст из @cloud-ru/ds-locale — оберните приложение в LocaleProvider.
Примеры использования
EmptyBlock со слотом действий
import { ButtonGroup } from '@cloud-ru/ds-button';
import { PlaceholderSVG } from '@cloud-ru/ds-icons/interface/system';
import { EmptyBlock } from '@cloud-ru/ds-uikit-product-layout';
export function EmptyBlockWithFooter() {
return (
<EmptyBlock
icon={{ icon: PlaceholderSVG }}
title='Нет данных'
content='Создайте первую запись, чтобы начать работу'
footer={<ButtonGroup primaryAction={{ label: 'Создать' }} secondaryAction={{ label: 'Импортировать' }} />}
/>
);
}NoAccess с названием сервиса
import { LocaleProvider } from '@cloud-ru/ds-locale';
import { NoAccess } from '@cloud-ru/ds-uikit-product-layout';
export function NoAccessBasic() {
return (
<LocaleProvider lang='ru-RU'>
<NoAccess serviceName='Название сервиса' />
</LocaleProvider>
);
}Props
EmptyBlock
Types
EmptyBlockProps| Prop | Type | Default | Required | Description |
|---|---|---|---|---|
align | "horizontal" | "vertical" | — | no | Выравнивание иконки и текста |
className | string | — | no | Дополнительный класс |
content | ReactNode | — | no | Описание под заголовком |
data-test-id | string | — | no | |
footer | ReactNode | — | no | Слот действий под текстом (например, `ButtonGroup`) |
icon | IconPredefinedProps | — | no | Иконка |
layoutPresets | Partial<Record<LayoutType, Partial<EmptyBlockLayoutDefaults>>> | — | no | Override mobile-дефолтов адаптива для этого инстанса (deep-merge поверх `EMPTY_BLOCK_LAYOUT_PRESETS`). Escape-hatch: обычно не нужен — DS-пресет применяется автоматически по `AdaptiveProvider`. |
title | string | — | no | Заголовок |
Types
EmptyBlockProps
EmptyBlockLayoutDefaults
Related props
Align
IconPredefinedProps
LayoutPresets
NoAccess
Types
NoAccessProps| Prop | Type | Default | Required | Description |
|---|---|---|---|---|
className | string | — | no | Дополнительный класс |
data-test-id | string | — | no | |
serviceName | string | — | no | Заголовок над блоком (например, название сервиса) |
Types
NoAccessProps
Адаптивность
Оба компонента читают раскладку из контекста @cloud-ru/ds-adaptive — отдельного пропа layoutType нет. Поставьте один <AdaptiveProvider> в корне приложения — mobile-поведение применяется автоматически.
Desktop-first. Верстайте под desktop; override нужен только как escape-hatch.
EmptyBlock
EmptyBlock — компонент класса preset-defaults: DOM один, по раскладке меняется дефолт align в InfoBlock.
| Проп | desktop | mobile |
|---|---|---|
align | horizontal | vertical |
Источник mobile-дефолтов — экспортируемая константа EMPTY_BLOCK_LAYOUT_PRESETS.
import { EmptyBlock } from '@cloud-ru/ds-uikit-product-layout'
// Явный проп — задаёт DESKTOP-значение; mobile остаётся vertical
<EmptyBlock align='horizontal' title='…' content='…' />
// Изменить mobile — только через layoutPresets
<EmptyBlock layoutPresets={{ mobile: { align: 'horizontal' } }} title='…' content='…' />
NoAccess
На mobile контейнер сужается (max-width: 360px); на desktop — широкий (max-width: 1200px). Отдельных адаптивных пропов нет — поведение полностью определяется раскладкой из AdaptiveProvider.
Подробнее о модели раскладки — в @cloud-ru/ds-adaptive.