GrButtonGroup
Берут, когда действия одного класса стоят рядом.
Обзор
Когда брать
- действия одного класса стоят рядом — панель инструментов, ряд «Сохранить / Отмена», переключатели вида;
- ряд должен читаться как одно целое — внутренние границы не задваиваются, скругления остаются по краям;
- оформление задаётся один раз —
size,toneиvariantраздаются всем кнопкам разом; - группе нужно имя —
ariaLabelобъясняет, что объединяет эти кнопки.
Когда взять другое
| Нужно | Берите |
|---|---|
| Выбирается значение, а не выполняется действие | GrSegmented |
| Действий много и они прячутся | GrDropdownMenu |
| Действие одно | GrButton |
| Разделы с разным содержимым | GrTabs |
Группа кнопок и сегменты выглядят похоже и означают разное: здесь каждая кнопка делает что-то и после нажатия ничего не остаётся выбранным, там один из вариантов всегда активен.
Варианты все тона и виды — настоящим компонентом
tone \ variant | primary | secondary | outline | ghost | ghost-border |
|---|---|---|---|---|---|
primary | |||||
neutral | |||||
success | |||||
warning | |||||
danger | |||||
info | |||||
slate | |||||
azure |
Размеры
xssmmdlg
Матрица живая: наводите и нажимайте. Состояний наведения, фокуса и нажатия здесь нет — они за браузером, а не за пропом.
Playground контролы выводятся из API, а не пишутся руками
Загружается…
0 изменено· состояние — в адресе
<GrButtonGroup>
<GrButton variant="outline">Board</GrButton>
<GrButton>List</GrButton>
<GrButton variant="outline">Calendar</GrButton>
</GrButtonGroup>Примеры 3 у каждого — живое демо и его код
Сегментированный переключатель одного контекста
Группа собирает соседние действия в один контрол: края склеены, нажатый сегмент — состояние экрана, а
aria-labelговорит, что именно переключают.Столбец и ряд с зазором
orientation="vertical"собирает кнопки в столбец и переносит скругления на верхний и нижний края;:attached="false"даёт обычный ряд, где каждая кнопка сохраняет свои радиусы и границы.
API порождается из пакета · разойтись не может
Props
| Prop | Type | по умолчанию | Описание |
|---|---|---|---|
tone |
| undefined | Тон всех кнопок группы. Проп самой кнопки сильнее. |
variant | GrButtonVariant | undefined | undefined | Вес всех кнопок группы: `primary`, `outline`, `ghost` и т. д. Проп самой кнопки сильнее. |
size | "xs" | "sm" | "md" | "lg" | undefined | undefined | Оформление, общее для кнопок группы. Проп самой кнопки сильнее. |
ariaLabel | string | undefined | undefined | Доступное имя группы: без него кнопки читаются как несвязанные. |
orientation | GrButtonGroupOrientation | undefined | "horizontal" | Направление ряда: `vertical` ставит кнопки столбцом. По умолчанию `horizontal`. |
attached | boolean | undefined | true | Склеивать кнопки в один блок. `false` — обычный ряд с зазором: каждая кнопка сохраняет свои радиусы и границы. В лотке не действует. |
appearance | GrButtonGroupAppearance | undefined | undefined | Вид группы. `default` — ряд по `attached`; `tray` — лоток: звенья лежат в общей подложке с зазором, прозрачные, а выбранное (`aria-pressed="true"` или `aria-current`) — лист с рамкой поверх лотка. Вес и тон звена в лотке решает группа, свой проп кнопки сильнее. По умолчанию `default`; тема меняет его через `componentDefaults` («Глина»). |
Слоты
| Slot | Type | Описание |
|---|---|---|
default | any | Кнопки группы. |
Типы
Все экспортируемые типы подпути, по файлам, где они объявлены. Имена, дженерики и тела читаются из файлов деклараций пакета и разойтись не могут.
import type { GrButtonGroupAppearance, GrButtonGroupContext, GrButtonGroupConfigurableProps } from '@feugene/granularity/components/GrButtonGroup'Файлdist/types/components/GrButtonGroup/config.d.ts
const grButtonGroupConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrButtonGroup">;Файлdist/types/components/shared/buttonGroupContext.d.ts
Вид группы: обычный ряд (склеенный или с зазором) или лоток — звенья в общей подложке.
type GrButtonGroupAppearance = 'default' | 'tray';Оформление, общее для кнопок группы. Каждое поле необязательно: группа задаёт только то, что задали ей, остальное кнопка решает сама.
type GrButtonGroupContext = {
size: ComputedRef<GrButtonSize | undefined>;
variant: ComputedRef<GrButtonVariant | undefined>;
tone: ComputedRef<GrButtonTone | undefined>;
/** Необязателен: контекст строят и руками. */
appearance?: ComputedRef<GrButtonGroupAppearance>;
};Контекст группы для GrButton.
Порядок разрешения оформления получается такой: проп кнопки → группа →
GrConfigProvider → дефолт. Группа ближе к кнопке, чем глобальный провайдер,
поэтому она и должна побеждать его, но не собственный проп кнопки.
function useGrButtonGroup(): GrButtonGroupContext | undefined;Файлdist/types/components/GrButtonGroup/defaults.d.ts
Пропы GrButtonGroup, которые можно задать глобально — темой
(componentDefaults в theme.json) или GrConfigProvider.
interface GrButtonGroupConfigurableProps {
appearance: GrButtonGroupAppearance;
}Файлdist/types/components/GrButtonGroup/GrButtonGroup.vue.d.ts
type GrButtonGroupOrientation = 'horizontal' | 'vertical';interface GrButtonGroupProps {
/** Доступное имя группы: без него кнопки читаются как несвязанные. */
ariaLabel?: string;
/** Направление ряда: `vertical` ставит кнопки столбцом. По умолчанию `horizontal`. */
orientation?: GrButtonGroupOrientation;
/**
* Склеивать кнопки в один блок. `false` — обычный ряд с зазором: каждая
* кнопка сохраняет свои радиусы и границы. В лотке не действует.
*/
attached?: boolean;
/**
* Вид группы. `default` — ряд по `attached`; `tray` — лоток: звенья лежат в
* общей подложке с зазором, прозрачные, а выбранное (`aria-pressed="true"` или
* `aria-current`) — лист с рамкой поверх лотка. Вес и тон звена в лотке
* решает группа, свой проп кнопки сильнее. По умолчанию `default`; тема меняет
* его через `componentDefaults` («Глина»).
*/
appearance?: GrButtonGroupAppearance;
/** Оформление, общее для кнопок группы. Проп самой кнопки сильнее. */
size?: GrButtonSize;
/** Вес всех кнопок группы: `primary`, `outline`, `ghost` и т. д. Проп самой кнопки сильнее. */
variant?: GrButtonVariant;
/** Тон всех кнопок группы. Проп самой кнопки сильнее. */
tone?: GrButtonTone;
}Использование из прозы библиотеки
Оформление одной строкой
<GrButtonGroup aria-label="Период" size="sm" variant="outline" tone="neutral">
<GrButton>День</GrButton>
<GrButton>Неделя</GrButton>
<GrButton tone="primary">Месяц</GrButton>
</GrButtonGroup>size, variant и tone группы доходят до кнопок через контекст. Порядок
разрешения: проп кнопки → группа → GrConfigProvider → дефолт — группа
ближе к кнопке, чем глобальный провайдер, поэтому побеждает его, но не
собственный проп кнопки.
Контекст доступен и снаружи — useGrButtonGroup(), если поверх группы строится
свой контрол.
Обёртки не разрывают ряд
Склейка считает звенья группы — прямых потомков, которые сами кнопка или
содержат кнопку. Поэтому кнопку можно завернуть в тултип, v-if-обёртку или
роутерную ссылку, и ряд останется целым:
<GrButtonGroup aria-label="Документ">
<GrButton>Открыть</GrButton>
<GrTooltip content="Копия появится рядом">
<GrButton>Дублировать</GrButton>
</GrTooltip>
</GrButtonGroup>Не-кнопочный потомок (разделитель, подпись) в склейку не входит и скругление себе не забирает.
Ориентация и режим без склейки
| Проп | Что делает |
|---|---|
orientation="vertical" | столбец: скругления переезжают на верхний и нижний края ряда |
:attached="false" | обычный ряд с зазором, каждая кнопка со своими радиусами |
Лоток
appearance="tray" — звенья не склеены, а лежат в общей подложке с полями и
зазором 2px. Невыбранное звено прозрачно, выбранное — лист с рамкой поверх лотка:
<GrButtonGroup appearance="tray" size="sm" aria-label="Период">
<GrButton :aria-pressed="range === 'day'" @click="range = 'day'">День</GrButton>
<GrButton :aria-pressed="range === 'week'" @click="range = 'week'">Неделя</GrButton>
</GrButtonGroup>- Выбранное — по
aria-pressed="true"илиaria-current. Своего состояния у кнопки нет: выбранность — атрибут, который потребитель и так обязан поставить ради скринридера, и лоток читает его же. - Вес и тон звена решает лоток: прозрачное
ghost, выбранноеsecondary, тонneutral. Свой проп кнопки сильнее,variantгруппы в лотке не действует,attached— тоже. - Подложка лотка —
--gr-muted, хук--gr-button-group-tray-bg.
Лоток — оформление, поэтому его задаёт и тема (componentDefaults: так он включён
у «Глины»), и GrConfigProvider.
Радиус
Внешние углы склеенной группы скругляет радиус ступени звеньев — тот же, что у
отдельной кнопки (--gr-button-radius-<ступень> темы); внутренние группа гасит сама.
Ручка приложения --gr-button-radius задаёт один радиус кнопкам и группам сразу,
--gr-button-group-radius — только внешним углам групп:
.app { --gr-button-radius: 12px; }Шов между solid-звеньями
Соседние primary-звенья в склеенной группе заливаются одним цветом и
сливаются: сплит-кнопка «Опубликовать ▾» читалась бы одной кнопкой с шевроном в
подписи. Поэтому второе из соседних solid-звеньев получает светлый шов в 1px —
слева в горизонтальной группе, сверху в вертикальной.
Группа ставит только переменную --gr-button-divider, а рисует шов тень самой
кнопки: собственный box-shadow из листа группы проиграл бы утилите кнопки при
любой специфичности. Звено, обёрнутое тултипом или ссылкой, шва не получает.
Доступность
Корень объявлен role="group"; имя задаётся пропом ariaLabel — без него набор
кнопок читается как несвязанный. Кнопка под курсором или с фокусом поднимается
над соседями, поэтому фокус-кольцо не срезается наложением границ.
Пропы этого примера