GrEmptyState
Берут, когда список пуст с самого начала.
Обзор
Когда брать
- список пуст с самого начала — «пока нет выплат»: объяснение и следующий шаг вместо пустого прямоугольника;
- фильтр ничего не нашёл — текст и действие тут другие: сбросить фильтр, а не создать первую запись;
- раздел ещё не настроен — иконка, заголовок, описание и кнопка вместо инструкции в поддержке;
- состояние встроено в другой компонент — списки, таблицы и графики показывают его слотом
#empty.
Когда взять другое
| Нужно | Берите |
|---|---|
| Данные грузятся | GrSkeleton / GrLoading |
| Запрос упал | GrResponseErrorBanner |
| Предупреждение в потоке страницы | GrAlert |
| Нужен просто текст без иллюстрации | GrCard |
Пустой экран без объяснения читается как поломка. Разница между «здесь пока ничего нет» и «по этому фильтру ничего не нашлось» — важна: в первом случае предлагают создать, во втором — снять фильтр.
Варианты все тона и виды — настоящим компонентом
variant
ghostoutlined
Размеры
xssmmdlg
Playground контролы выводятся из API, а не пишутся руками
Загружается…
0 изменено· состояние — в адресе
<GrEmptyState title="No invoices yet" description="Create the first one, or bring last year's from a CSV."><GrButton size="sm">New invoice</GrButton></GrEmptyState>Примеры 3 у каждого — живое демо и его код
Первый день списка счетов
Там, где будут строки, пустое состояние предлагает действия, которые их заполнят: кнопки — в слоте по умолчанию, а описание говорит, что будет дальше, а не что список пуст.
variant="ghost"— список уже рамка; как только счёт создан, список занимает место пустоты.InvoicesNo invoices yet
Create the first one, or bring last year's from a CSV. Clients get each invoice by email with a payment link.«Не нашлось» — не то же, что «ещё нет»
kind="search"рисует лупу и называет другую пустоту. Слотtitleцитирует запрос, чтобы опечатка была видна, а действия правят запрос или расширяют поиск на архивных клиентов. Предложить здесь создать клиента — ответить на другой вопрос.No customers match «nortwind»
Archived customers are not searched by default.Пустая карточка — хорошая новость
Внутри карточки
size="sm"сvariant="ghost"не дают пустоте нарисовать вторую рамку и крупную картинку. Слотiconставит зелёный щит вместо пустого листа — отсутствие споров и есть ответ, которого ждали, — аheading-levelследует за заголовком карточки.Recent payments
Northwind2 min ago€1,284.50Contoso1 h ago€432.00Fabrikamyesterday€96.00Open disputes
No open disputes
Chargebacks appear here within an hour of the bank's notice.
API порождается из пакета · разойтись не может
Props
| Prop | Type | по умолчанию | Описание |
|---|---|---|---|
variant | "ghost" | "outlined" | undefined | undefined | `ghost` снимает рамку и фон: карточка внутри карточки рисует вторую рамку. |
title | string | undefined | undefined | Заголовок. Не задан — берётся из локали; слот `#title` сильнее обоих. |
size | "xs" | "sm" | "md" | "lg" | undefined | undefined | Масштаб иконки, текста и отступов. По умолчанию `md`; берётся из `GrConfigProvider`. |
description | string | undefined | undefined | Пояснение под заголовком: почему пусто и что сделать. Слот `#description` сильнее. |
headingLevel | 2 | 3 | 4 | 5 | 6 | undefined | undefined | Уровень заголовка (`h2`…`h6`) — под структуру страницы. По умолчанию `3`. |
kind | "search" | "empty" | undefined | "empty" | Что за пустота: ещё ничего не создано (`empty`) или под запросом ничего не нашлось (`search`). Меняет иконку и заголовок по умолчанию; заданный `title` сильнее в обоих случаях. |
Слоты
| Slot | Type | Описание |
|---|---|---|
icon | any | Иконка вместо встроенной. |
title | any | Заголовок разметкой: ссылка, выделение, счётчик. |
description | any | Пояснение разметкой — со ссылкой или выделением; сильнее `description`. |
default | any | Действия под текстом: центрируются. |
Типы
Все экспортируемые типы подпути, по файлам, где они объявлены. Имена, дженерики и тела читаются из файлов деклараций пакета и разойтись не могут.
import type { GrEmptyStateProps, GrEmptyStateConfigurableProps, GrEmptyStateSize } from '@feugene/granularity/components/GrEmptyState'Файлdist/types/components/GrEmptyState/GrEmptyState.vue.d.ts
GrEmptyState — карточка пустого состояния: иконка, заголовок, описание и слот действий. Заголовок — настоящий heading: без него пустое состояние не находится навигацией по заголовкам, а именно оно и объясняет, почему на экране ничего нет.
interface GrEmptyStateProps {
/** Заголовок. Не задан — берётся из локали; слот `#title` сильнее обоих. */
title?: string;
/** Пояснение под заголовком: почему пусто и что сделать. Слот `#description` сильнее. */
description?: string;
/** Масштаб иконки, текста и отступов. По умолчанию `md`; берётся из `GrConfigProvider`. */
size?: GrEmptyStateSize;
/** `ghost` снимает рамку и фон: карточка внутри карточки рисует вторую рамку. */
variant?: GrEmptyStateVariant;
/** Уровень заголовка (`h2`…`h6`) — под структуру страницы. По умолчанию `3`. */
headingLevel?: GrEmptyStateHeadingLevel;
/**
* Что за пустота: ещё ничего не создано (`empty`) или под запросом ничего не
* нашлось (`search`). Меняет иконку и заголовок по умолчанию; заданный
* `title` сильнее в обоих случаях.
*/
kind?: GrEmptyStateKind;
}Файлdist/types/components/GrEmptyState/config.d.ts
const grEmptyStateConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrEmptyState">;Файлdist/types/components/GrEmptyState/defaults.d.ts
Пропы GrEmptyState, настраиваемые глобально через
<GrConfigProvider :component-defaults="{ GrEmptyState: { … } }">.
Только оформление — см. GrButton/defaults.ts.
interface GrEmptyStateConfigurableProps {
size: GrEmptyStateSize;
variant: GrEmptyStateVariant;
headingLevel: GrEmptyStateHeadingLevel;
}Файлdist/types/components/GrEmptyState/grEmptyStateStyles.d.ts
type GrEmptyStateSize = GrComponentSize;type GrEmptyStateVariant = typeof GR_EMPTY_STATE_VARIANTS[number];type GrEmptyStateKind = typeof GR_EMPTY_STATE_KINDS[number];type GrEmptyStateHeadingLevel = typeof GR_EMPTY_STATE_HEADING_LEVELS[number];Файлdist/types/components/GrEmptyState/safelist.d.ts
const grEmptyStateSafelist: string[];Использование из прозы библиотеки
Две пустоты, а не одна
kind различает то, что пользователь видит по-разному:
kind | Когда | Заголовок и иконка по умолчанию |
|---|---|---|
empty (по умолчанию) | ещё ничего не создано | «Пока пусто», ящик |
search | под запросом или фильтром ничего не нашлось | «Ничего не найдено», лупа с крестом |
Разница не косметическая. Под фильтром «Пока пусто» дезинформирует: данные есть, просто не совпали, и следующий шаг у пользователя другой — не «создать», а «ослабить запрос».
Значений ровно два, потому что столько повторяется. Ошибка загрузки сюда не
входит намеренно: у неё в пакете свои компоненты —
GrResponseErrorBanner.
Описание по умолчанию не подставляется ни в одном из видов: оно всегда про конкретный экран, и угадать его нечем.
Заголовок
<GrEmptyState title="Пока нет выплат" description="Создайте первую выплату, чтобы отслеживать согласования.">
<GrButton size="sm">Создать выплату</GrButton>
</GrEmptyState>Заголовок — настоящий heading: без него пустое состояние не находится
навигацией по заголовкам, а объясняет происходящее на экране именно оно.
Уровень задаётся headingLevel (2…6, по умолчанию 3) и настраивается
глобально через componentDefaults.GrEmptyState.headingLevel. h1 в наборе нет
намеренно: пустое состояние живёт внутри уже существующей структуры страницы, а
не задаёт её.
title необязателен: без него и без слота берётся строка из локали
(gr.emptyState.title), так что <GrEmptyState /> не превращается в пустую
карточку.
Слоты
| Слот | Зачем |
|---|---|
title | заголовок разметкой: ссылка, выделение, счётчик |
description | описание разметкой |
icon | своя иконка вместо встроенной lucide/inbox |
| по умолчанию | действия под текстом, центрируются |
Слот сильнее одноимённого пропа. Встроенная иконка декоративна
(aria-hidden) — смысл несёт текст.
Поверхность
<GrCard>
<GrEmptyState variant="ghost" title="Никого не пригласили" />
</GrCard>variant (outlined по умолчанию, ghost) повторяет словарь
GrCard: ghost снимает рамку, фон и радиус. Он нужен внутри
уже существующей карточки — в GrDataTable #empty, GrList #empty или в своём
макете, где outlined даёт вторую рамку вокруг той же поверхности.
Размер
size (xs…lg, по умолчанию md, читается из GrConfigProvider) двигает
падинг карточки, коробку иконки, саму иконку, кегль заголовка и вертикальные
отступы. xs и sm — для пустой ячейки таблицы и панели дропдауна, где
полноразмерное состояние занимает весь список.
Оформление
Всё берётся из токенов: радиус — --gr-radius-md/--gr-radius-lg по ступени,
кегли — --gr-text-xs/--gr-text-sm/--gr-text-base, цвета — --gr-card,
--gr-brd, --gr-muted, --gr-muted-fg.
Пропы этого примера