GrBadgeWrap
Берут, когда счётчик относится к контролу.
Обзор
Когда брать
- счётчик относится к контролу — непрочитанные на иконке почты, товары в корзине, задачи на вкладке;
- важен сам факт, а не число —
dotпоказывает точку без цифры; - число может быть большим —
maxсворачивает его в «99+»; - ноль надо показать —
showZero; по умолчанию счётчик исчезает, а не рисует «0».
Когда взять другое
| Нужно | Берите |
|---|---|
| Метка стоит в потоке, а не поверх контрола | GrBadge |
| Статус присутствия на аватаре | GrAvatar |
| Счётчик — часть вкладки | GrTabs с badge |
| Счётчик — часть раздела навигации | GrBottomNav с badge |
Варианты все тона и виды — настоящим компонентом
tone
primaryneutralsuccesswarningdangerinfoslateazure
Playground контролы выводятся из API, а не пишутся руками
Загружается…
0 изменено· состояние — в адресе
<GrBadgeWrap :value="3"><GrButton variant="outline">Inbox</GrButton></GrBadgeWrap>Примеры 4 у каждого — живое демо и его код
Шапка приложения: сколько и насколько срочно
Срочность несёт тон: красный оставлен тревогам, которые требуют действия сегодня, а длинная очередь сообщений — спокойный primary.
maxсворачивает 128 в «99+», аaria-labelсохраняет для скринридера настоящее число. Факт без числа —dot, и на круглом аватаре точка сама садится на окружность.Acme Billing 128 unread messages3 alerts need actionALBilling details are missingНовые сообщения и упоминания — два угла одной плитки
У пространства с упоминаниями обычно есть и новые сообщения, и панель показывает оба: точка сверху говорит «что-то случилось», число снизу —
placement="bottom-right"— сколько раз позвали вас. Откройте пространство, и метки переходят в список каналов: там счётчик стоит в строке, и это ужеGrBadge.Acme BillingСчётчик, который вздрагивает только от новостей
animateотмечает то, чего покупатель ещё не знает: появление счётчика и рост числа. Убрать товар — его собственное действие, и число уменьшается молча, а на нуле счётчик вовсе уходит с иконки. Спокойный тонneutralподходит корзине — тревоги в ней нет.Northwind Office1 items in the cartOffice chair, oak€349 · ships in 3 daysIn the cart: €349Ноль — это ответ
Отчёты, сохранённые без связи, ждут в исходящих. По умолчанию ноль убирает счётчик, но здесь «отправлять нечего» — ровно то, что инспектор проверяет перед уходом с объекта:
show-zeroоставляет его, а тон меняется с warning на success. Синхронизация опустошает очередь без «попа», новый отчёт возвращает его.Bremen yardReport #2041 Outbox 2 reports waiting to be sent2 waiting · last sync 09:40
API порождается из пакета · разойтись не может
Props
| Prop | Type | по умолчанию | Описание |
|---|---|---|---|
placement | "top-right" | "top-left" | "bottom-right" | "bottom-left" | undefined | "top-right" | Угол, в котором висит метка. По умолчанию `top-right`. Сдвиг от угла — переменные `--gr-badge-wrap-offset-x/-y`. |
tone |
| "danger" | Цвет метки из шкалы тонов: заливка — роль тона, текст — её `-fg`. По умолчанию `danger`. |
ariaLabel | string | undefined | undefined | Подпись счётчика для скринридера. Не задана — берётся из локали. |
value | string | number | undefined | undefined | Значение счётчика: число или короткая строка («NEW»). Не задано — счётчика нет; ноль скрыт, пока не включён `showZero`. |
dot | boolean | undefined | false | Точка вместо числа: чистая декорация, если не задан `ariaLabel`. |
max | number | undefined | undefined | Порог: значения больше него рисуются как «{max}+». |
showZero | boolean | undefined | false | Показывать ли нулевое значение. По умолчанию ноль скрыт. |
animate | boolean | undefined | false | Отмечать ли появление и рост **счётчика** анимацией. Точке анимировать нечего. |
Слоты
| Slot | Type | Описание |
|---|---|---|
default | any | Элемент, к которому крепится метка. |
Типы
Все экспортируемые типы подпути, по файлам, где они объявлены. Имена, дженерики и тела читаются из файлов деклараций пакета и разойтись не могут.
import type { GrBadgeWrapProps, GrBadgeWrapTone, GrBadgeWrapPlacement } from '@feugene/granularity/components/GrBadgeWrap'Файлdist/types/components/GrBadgeWrap/GrBadgeWrap.vue.d.ts
GrBadgeWrap — обёртка, вешающая на потомка счётчик или точку-индикатор. Число объявляется скринридеру: «3» без единицы измерения ничего не значит, поэтому рядом с бейджем идёт визуально скрытая подпись.
interface GrBadgeWrapProps {
/**
* Значение счётчика: число или короткая строка («NEW»). Не задано — счётчика
* нет; ноль скрыт, пока не включён `showZero`.
*/
value?: string | number;
/** Точка вместо числа: чистая декорация, если не задан `ariaLabel`. */
dot?: boolean;
/** Порог: значения больше него рисуются как «{max}+». */
max?: number;
/** Показывать ли нулевое значение. По умолчанию ноль скрыт. */
showZero?: boolean;
/** Цвет метки из шкалы тонов: заливка — роль тона, текст — её `-fg`. По умолчанию `danger`. */
tone?: GrBadgeWrapTone;
/**
* Угол, в котором висит метка. По умолчанию `top-right`. Сдвиг от угла —
* переменные `--gr-badge-wrap-offset-x/-y`.
*/
placement?: GrBadgeWrapPlacement;
/** Подпись счётчика для скринридера. Не задана — берётся из локали. */
ariaLabel?: string;
/** Отмечать ли появление и рост **счётчика** анимацией. Точке анимировать нечего. */
animate?: boolean;
}Файлdist/types/components/GrBadgeWrap/config.d.ts
const grBadgeWrapConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrBadgeWrap">;Файлdist/types/components/GrBadgeWrap/grBadgeWrapStyles.d.ts
type GrBadgeWrapTone = GrTone;type GrBadgeWrapPlacement = typeof GR_BADGE_WRAP_PLACEMENTS[number];Видимый текст счётчика: число больше порога сворачивается в «{max}+», иначе бейдж расползается и ломает соседей. Озвучивается при этом настоящее значение — «99 плюс» пользователю ничего не говорит.
function formatBadgeValue(value: string | number, max?: number): string;Файлdist/types/components/GrBadgeWrap/safelist.d.ts
const grBadgeWrapSafelist: string[];Использование из прозы библиотеки
Счётчик
<GrBadgeWrap :value="3">
<GrButton size="sm" variant="outline">Inbox</GrButton>
</GrBadgeWrap>Число рисуется декоративно, а рядом идёт визуально скрытая подпись — иначе
диктор читал бы «Inbox, 3» без единицы измерения либо не читал счётчик вовсе.
Текст берётся из локали (gr.badgeWrap.count), ariaLabel перебивает его.
Ноль по умолчанию не показывается: пустой кружок на иконке читается как ошибка.
showZero возвращает его, когда ноль — осмысленное состояние («0 черновиков»).
Обрезка крупных чисел
<GrBadgeWrap :value="120" :max="99">
<GrButton size="sm" variant="outline">Inbox</GrButton>
</GrBadgeWrap>Видно «99+», а озвучивается настоящее число: «120 непрочитанных». «99 плюс» пользователю ничего не сообщает.
Функция доступна отдельно: import { formatBadgeValue } from '@feugene/granularity'.
Точка
<GrBadgeWrap dot aria-label="Есть непрочитанные">
<GrAvatar :size="40">AD</GrAvatar>
</GrBadgeWrap>Точка не несёт числа и остаётся декоративной, пока ей не задали ariaLabel, —
тогда факт события объявляется словом. Годится, когда важно «требует внимания»,
а не «сколько именно».
Ребёнок обязателен. Метка позиционируется абсолютно относительно корня, а
корень без содержимого имеет нулевой размер: точка нарисуется вокруг пустого
места, не займёт в раскладке ничего и налезет на соседей. Нужен статус-маркер
сам по себе, в потоке, — это dot у GrBadge.
Анимация счётчика
<GrBadgeWrap :value="unread" animate>
<GrButton size="sm" variant="outline">Inbox</GrButton>
</GrBadgeWrap>animate отмечает «попом» то, о чём пользователь ещё не знает: появление
счётчика и рост числа. Убыль — след его собственного действия, и подсвечивать
её значит мигать бейджем на каждом прочитанном письме.
| Переход | Что происходит |
|---|---|
| счётчика не было → появился | «поп» |
| число выросло | «поп» |
| число уменьшилось | молча |
| счётчик исчез | молча |
| первый рендер страницы | молча |
Строковое значение (value="NEW") порядка не имеет, поэтому любая его смена
считается событием.
Пачка изменений даёт один «поп»: пока анимация играет, новое значение её не перезапускает. Пять писем, пришедших за секунду, отмечаются одним движением, а не мельтешением.
По умолчанию animate выключен. Уместна ли анимация, знает приложение: счётчик,
который меняется раз в час, и счётчик, который меняется постоянно, — разные
случаи, и библиотека выбирает за потребителя тихий.
Точка (dot) в анимации не участвует: у неё нет значения, и «рост» для неё не
определён.
Движение подчиняется prefers-reduced-motion через глобальный кламп пакета —
подробности в motion.md. Длительность и кривая берутся из
--gr-duration-base и --gr-ease-out, то есть настраиваются темой вместе со
всем остальным движением.
Тон и положение
| Проп | Значения | По умолчанию |
|---|---|---|
tone | вся шкала GR_TONES (neutral, primary, success, warning, danger, info, slate, azure) | danger |
placement | top-right | top-left | bottom-right | bottom-left | top-right |
Цвет текста берётся из парного токена --gr-<tone>-fg, а не из белого литерала:
бейдж переживает смену темы.
Смещение от угла настраивается переменными — темой или инлайн-стилем:
<GrBadgeWrap :value="3" style="--gr-badge-wrap-offset-x: -0.75rem" />| Переменная | По умолчанию (счётчик / точка) |
|---|---|
--gr-badge-wrap-offset-x | -0.5rem / 0 |
--gr-badge-wrap-offset-y | -0.5rem / 0 |
Точка по умолчанию не выходит за рамку: угол рамки у скруглённой кнопки и у
круглого аватара пуст, и точка с центром на нём висела бы рядом с контролом.
С нулевым сдвигом она садится на дугу скругления или на край круга — как
статусная точка GrAvatar. Счётчик крупнее и перекрывает скругление и так.
Почему не GrBadge внутри
Обёртка рисует свой минимальный бейдж намеренно: иначе каждый счётчик тянул бы за собой полноразмерный компонент со своей шкалой размеров и радиусов ради кружка в 20 пикселей.
Пропы этого примера