GrNavbar
Берут, когда у приложения есть верхняя панель.
Обзор
Когда брать
- у приложения есть верхняя панель — заголовок, поиск, профиль, уведомления в трёх зонах;
- панель должна оставаться видимой —
stickyпри прокрутке длинных страниц; - на мобильном нужна кнопка меню —
showMenuButtonоткрываетGrDrawerилиGrSidebar; - нужен лендмарк
banner— корень рендерится тегом<header>, и обход по ориентирам работает.
Когда взять другое
| Нужно | Берите |
|---|---|
| Боковая навигация | GrSidebar |
| Нижняя панель разделов на мобильном | GrBottomNav |
| Панель действий над таблицей или дашбордом | GrButtonGroup / GrDashboardToolbar |
| Путь до текущей страницы | GrBreadcrumbs |
Playground контролы выводятся из API, а не пишутся руками
Загружается…
0 изменено· состояние — в адресе
<GrNavbar title="Granularity" />Примеры 3 у каждого — живое демо и его код
API порождается из пакета · разойтись не может
Props
| Prop | Type | по умолчанию | Описание |
|---|---|---|---|
title | string | undefined | undefined | Заголовок строкой. Слот `#title` сильнее и позволяет обойтись без пропа. |
size | "xs" | "sm" | "md" | "lg" | undefined | undefined | Ступень кнопки меню — и только её: остальное в шапке принадлежит потребителю, а высоту ряда задаёт `--gr-navbar-height`. Фолбэк — `sm` (32px), а не общий для пакета `md`: кнопка была этого размера с самого начала, и подъём по умолчанию сдвинул бы шапку у всех. Нужен тач-таргет — `size="lg"` даёт 44px, ровно то, чего требуют WCAG 2.5.5 и Apple HIG; в 56px ряда он помещается. |
headingLevel | 2 | 1 | 3 | 4 | 5 | 6 | undefined | undefined | Сделать заголовок настоящим `h1`…`h6`. По умолчанию заголовок — `div`, и это верно для большинства шапок: логотип и название приложения заголовками не являются, и `h1` на них исказил бы структуру страницы. Но шапка раздела админки или имя документа — заголовок и есть, а обойти такую страницу по структуре иначе нечем. Через `GrConfigProvider` не настраивается намеренно: «заголовка нет» там не выразить (`useGrComponentProp` требует не-nullable фолбэк), то есть общим дефолтом стал бы какой-то уровень. Да и шапка у оболочки одна — глобальный дефолт настраивал бы единственное место вызова. |
showMenuButton | boolean | undefined | false | Кнопка-«бургер» слева от заголовка; нажатие приходит событием `menu`. По умолчанию `false`. |
menuButtonClass | string | undefined | "" | Extra classes applied to the menu button wrapper (e.g. `sm:hidden`). |
sticky | boolean | undefined | false | Панель прилипает к верху при прокрутке. Слой — `--gr-z-navbar`: он ниже якорных панелей, чтобы открытый список не уезжал под шапку. |
Слоты
| Slot | Type | Описание |
|---|---|---|
title | any | Заголовок целиком — вместо строки `title`. |
left | any | Зона сразу после заголовка: вкладки, переключатель раздела. |
center | any | Центральная зона: поиск, хлебные крошки. |
default | any | Правая зона: действия, аватар. |
События
| Event | Сигнатура | Описание |
|---|---|---|
menu | (event: "menu"): void | — |
Типы
Все экспортируемые типы подпути, по файлам, где они объявлены. Имена, дженерики и тела читаются из файлов деклараций пакета и разойтись не могут.
import type { GrNavbarProps, GrNavbarEmits, GrNavbarHeadingLevel } from '@feugene/granularity/components/GrNavbar'Файлdist/types/components/GrNavbar/GrNavbar.vue.d.ts
GrNavbar — верхняя панель приложения (header) с тремя зонами: слева заголовок
и кнопка меню, по центру — свободная зона (поиск, хлебные крошки), справа —
действия и аватар.
- Корень — <header> (landmark), без собственного role.
- aria-label кнопки меню локализуется через useGranularityTranslations.
interface GrNavbarProps {
/** Заголовок строкой. Слот `#title` сильнее и позволяет обойтись без пропа. */
title?: string;
/**
* Сделать заголовок настоящим `h1`…`h6`.
*
* По умолчанию заголовок — `div`, и это верно для большинства шапок: логотип
* и название приложения заголовками не являются, и `h1` на них исказил бы
* структуру страницы. Но шапка раздела админки или имя документа — заголовок
* и есть, а обойти такую страницу по структуре иначе нечем.
*
* Через `GrConfigProvider` не настраивается намеренно: «заголовка нет» там не
* выразить (`useGrComponentProp` требует не-nullable фолбэк), то есть общим
* дефолтом стал бы какой-то уровень. Да и шапка у оболочки одна — глобальный
* дефолт настраивал бы единственное место вызова.
*/
headingLevel?: GrNavbarHeadingLevel;
/** Кнопка-«бургер» слева от заголовка; нажатие приходит событием `menu`. По умолчанию `false`. */
showMenuButton?: boolean;
/**
* Ступень кнопки меню — и только её: остальное в шапке принадлежит
* потребителю, а высоту ряда задаёт `--gr-navbar-height`.
*
* Фолбэк — `sm` (32px), а не общий для пакета `md`: кнопка была этого размера
* с самого начала, и подъём по умолчанию сдвинул бы шапку у всех. Нужен
* тач-таргет — `size="lg"` даёт 44px, ровно то, чего требуют WCAG 2.5.5 и
* Apple HIG; в 56px ряда он помещается.
*/
size?: GrComponentSize;
/** Extra classes applied to the menu button wrapper (e.g. `sm:hidden`). */
menuButtonClass?: string;
/**
* Панель прилипает к верху при прокрутке. Слой — `--gr-z-navbar`: он ниже
* якорных панелей, чтобы открытый список не уезжал под шапку.
*/
sticky?: boolean;
}interface GrNavbarEmits {
/** Нажата кнопка меню — сигнал открыть боковую навигацию. */
(e: 'menu'): void;
}Файлdist/types/components/GrNavbar/grNavbarStyles.d.ts
type GrNavbarHeadingLevel = typeof GR_NAVBAR_HEADING_LEVELS[number];Файлdist/types/components/GrNavbar/defaults.d.ts
Пропы GrNavbar, настраиваемые глобально через componentDefaults.
interface GrNavbarConfigurableProps {
size: GrComponentSize;
}Файлdist/types/components/GrNavbar/config.d.ts
const grNavbarConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrNavbar">;Файлdist/types/components/GrNavbar/safelist.d.ts
const grNavbarSafelist: string[];Использование из прозы библиотеки
Заголовок настоящим heading — по запросу
<GrNavbar title="Договоры" :heading-level="1" />По умолчанию заголовок шапки — div, и это не упущение: логотип и название
приложения заголовками не являются, а h1 на бренде исказил бы структуру
страницы. Большинство шапок именно такие.
Но шапка раздела админки или имя открытого документа — заголовок и есть, и без
headingLevel обойти такую страницу по структуре нечем: после h1 в ней не
оказывается ни одного заголовка.
Единица разрешена, в отличие от GrCard, где шкала
начинается с двойки. Карточка никогда не бывает заголовком страницы, а шапка
раздела — бывает.
Через GrConfigProvider уровень не настраивается намеренно. «Заголовка нет» там
не выразить, то есть общим дефолтом стал бы какой-то уровень — и брендовые шапки
всех потребителей молча получили бы заголовок. Да и шапка у оболочки одна:
глобальный дефолт настраивал бы единственное место вызова.
Вид от уровня не зависит: кегль и вес те же, а браузерный отступ заголовка
погашен явно. Префлайт пакета сбрасывает margin только у body, поэтому
приложение с tailwind-совместимым сбросом его и не увидело бы, — но высота шапки
не должна зависеть от того, подключил ли потребитель чужой reset.
Три зоны
<GrNavbar>
<template #title>
<RouterLink to="/">Granularity</RouterLink>
</template>
<template #center>
<GrInput placeholder="Поиск" size="sm" aria-label="Поиск" />
</template>
<GrButton size="sm">Опубликовать</GrButton>
</GrNavbar>| Слот | Где |
|---|---|
title | слева, после кнопки меню; заменяет строку title |
left | сразу за заголовком — вкладки, переключатель раздела |
center | по центру панели — поиск, хлебные крошки |
| по умолчанию | справа — действия, аватар |
Проп title необязателен: заголовок собирается разметкой через слот. Когда нет
ни строки, ни слота, блок заголовка не рендерится и не съедает отступ.
Центральная зона появляется только вместе со слотом. При ней боковые зоны делят остаток поровну — иначе «центр» считался бы от остатка и уезжал вслед за более широким боком.
Когда места не хватает
Действия справа — глобальный интерфейс: поиск, уведомления, аватар. Эта зона
не сжимается никогда. Уступают left и center: они не шире остатка и
прокручиваются вбок без видимой полосы. Прокрутка, а не обрезка — ссылка за
краем остаётся достижимой, фокус с клавиатуры прокручивает зону к ней. Раньше
переполненный left рисовался поверх действий: на 600px «Reports» ложился на
«Search». Действий шире своей доли при центральной зоне — тоже без сжатия:
центр в этом случае смещается, но ничего не перекрывает.
Шапка с большим числом разделов на узком экране — повод убрать их в меню
(showMenuButton), а не надеяться на прокрутку.
Прилипание
<GrNavbar sticky />sticky оставляет панель наверху при прокрутке. Слой — --gr-z-navbar (900):
ниже якорных панелей (--gr-z-dropdown — 1000), поэтому открытый список,
тултип или модалка панель перекрывают, а не уезжают под неё. Подробности —
../z-index.md.
Высота
Задаётся переменной --gr-navbar-height (по умолчанию 56px) — на самой
панели, на предке или в теме:
.app-shell { --gr-navbar-height: 48px; }Кнопка меню
showMenuButton показывает кнопку и эмитит menu; её доступное имя приходит из
локали (gr.navbar.openMenu). menuButtonClass нужен, чтобы прятать кнопку на
широких экранах (sm:hidden) — панель не решает за приложение, когда меню
сворачивается.
size задаёт ступень только этой кнопки — остальное в шапке принадлежит
потребителю, а высоту ряда держит --gr-navbar-height. Читается из
GrConfigProvider (componentDefaults.GrNavbar.size).
Фолбэк — sm (32px), а не общий для пакета md: кнопка была этого размера с
самого начала, и подъём по умолчанию сдвинул бы шапку у всех. Нужен полноценный
тач-таргет — size="lg" даёт 44px и помещается в ряд высотой 56px.
Пропы этого примера