GrButtonGroup

  • ядро
  • Действия
  • API · 6 props

Берут, когда действия одного класса стоят рядом.

import { GrButtonGroup } from '@feugene/granularity/components/GrButtonGroup'

Обзор

Когда брать

  • действия одного класса стоят рядом — панель инструментов, ряд «Сохранить / Отмена», переключатели вида;
  • ряд должен читаться как одно целое — внутренние границы не задваиваются, скругления остаются по краям;
  • оформление задаётся один раз — size, tone и variant раздаются всем кнопкам разом;
  • группе нужно имя — ariaLabel объясняет, что объединяет эти кнопки.

Когда взять другое

НужноБерите
Выбирается значение, а не выполняется действиеGrSegmented
Действий много и они прячутсяGrDropdownMenu
Действие одноGrButton
Разделы с разным содержимымGrTabs

Группа кнопок и сегменты выглядят похоже и означают разное: здесь каждая кнопка делает что-то и после нажатия ничего не остаётся выбранным, там один из вариантов всегда активен.

Варианты все тона и виды — настоящим компонентом

Варианты · GrButtonGroup
tone \ variantprimarysecondaryoutlineghostghost-border
primary
neutral
success
warning
danger
info
slate
azure

Размеры

  • xs
  • sm
  • md
  • lg

Матрица живая: наводите и нажимайте. Состояний наведения, фокуса и нажатия здесь нет — они за браузером, а не за пропом.

Playground контролы выводятся из API, а не пишутся руками

Сцена

Загружается…

0 изменено· состояние — в адресе

Примеры 3 у каждого — живое демо и его код

  • Сегментированный переключатель одного контекста

    Группа собирает соседние действия в один контрол: края склеены, нажатый сегмент — состояние экрана, а aria-label говорит, что именно переключают.

  • Размер, вид и тон заданы один раз

    size, variant и tone заданы на группе и доходят до каждой кнопки; проп самой кнопки по-прежнему сильнее — так опасное действие остаётся красным в нейтральном ряду.

  • Столбец и ряд с зазором

    orientation="vertical" собирает кнопки в столбец и переносит скругления на верхний и нижний края; :attached="false" даёт обычный ряд, где каждая кнопка сохраняет свои радиусы и границы.

API порождается из пакета · разойтись не может

Props

PropTypeпо умолчаниюОписание
tone
"primary" | "neutral" | "success" | "warning" | "danger" | ""primary" | "neutral" | "success" | "warning" | "danger" | "info" | "slate" | "azure" | undefined
undefinedТон всех кнопок группы. Проп самой кнопки сильнее.
variantGrButtonVariant | undefinedundefinedВес всех кнопок группы: `primary`, `outline`, `ghost` и т. д. Проп самой кнопки сильнее.
size"xs" | "sm" | "md" | "lg" | undefinedundefinedОформление, общее для кнопок группы. Проп самой кнопки сильнее.
ariaLabelstring | undefinedundefinedДоступное имя группы: без него кнопки читаются как несвязанные.
orientationGrButtonGroupOrientation | undefined"horizontal"Направление ряда: `vertical` ставит кнопки столбцом. По умолчанию `horizontal`.
attachedboolean | undefinedtrueСклеивать кнопки в один блок. `false` — обычный ряд с зазором: каждая кнопка сохраняет свои радиусы и границы.

Слоты

SlotTypeОписание
defaultanyКнопки группы.

Типы

Все экспортируемые типы подпути, по файлам, где они объявлены. Имена, дженерики и тела читаются из файлов деклараций пакета и разойтись не могут.

Импорт
import type { GrButtonGroupContext, GrButtonGroupOrientation, GrButtonGroupProps } from '@feugene/granularity/components/GrButtonGroup'

Файлdist/types/components/GrButtonGroup/config.d.ts

grButtonGroupConfigconst
const grButtonGroupConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrButtonGroup">;

Файлdist/types/components/shared/buttonGroupContext.d.ts

GrButtonGroupContexttype

Оформление, общее для кнопок группы. Каждое поле необязательно: группа задаёт только то, что задали ей, остальное кнопка решает сама.

type GrButtonGroupContext = {
    size: ComputedRef<GrButtonSize | undefined>;
    variant: ComputedRef<GrButtonVariant | undefined>;
    tone: ComputedRef<GrButtonTone | undefined>;
};
useGrButtonGroupfunction

Контекст группы для GrButton. Порядок разрешения оформления получается такой: проп кнопки → группа → GrConfigProvider → дефолт. Группа ближе к кнопке, чем глобальный провайдер, поэтому она и должна побеждать его, но не собственный проп кнопки.

function useGrButtonGroup(): GrButtonGroupContext | undefined;

Файлdist/types/components/GrButtonGroup/GrButtonGroup.vue.d.ts

GrButtonGroupOrientationtype
type GrButtonGroupOrientation = 'horizontal' | 'vertical';
GrButtonGroupPropsinterface
interface GrButtonGroupProps {
    /** Доступное имя группы: без него кнопки читаются как несвязанные. */
    ariaLabel?: string;
    /** Направление ряда: `vertical` ставит кнопки столбцом. По умолчанию `horizontal`. */
    orientation?: GrButtonGroupOrientation;
    /**
     * Склеивать кнопки в один блок. `false` — обычный ряд с зазором: каждая
     * кнопка сохраняет свои радиусы и границы.
     */
    attached?: boolean;
    /** Оформление, общее для кнопок группы. Проп самой кнопки сильнее. */
    size?: GrButtonSize;
    /** Вес всех кнопок группы: `primary`, `outline`, `ghost` и т. д. Проп самой кнопки сильнее. */
    variant?: GrButtonVariant;
    /** Тон всех кнопок группы. Проп самой кнопки сильнее. */
    tone?: GrButtonTone;
}

Использование из прозы библиотеки

Оформление одной строкой
vue
<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-обёртку или роутерную ссылку, и ряд останется целым:

vue
<GrButtonGroup aria-label="Документ">
  <GrButton>Открыть</GrButton>
  <GrTooltip content="Копия появится рядом">
    <GrButton>Дублировать</GrButton>
  </GrTooltip>
</GrButtonGroup>

Не-кнопочный потомок (разделитель, подпись) в склейку не входит и скругление себе не забирает.

Ориентация и режим без склейки
ПропЧто делает
orientation="vertical"столбец: скругления переезжают на верхний и нижний края ряда
:attached="false"обычный ряд с зазором, каждая кнопка со своими радиусами
Радиус

Группа берёт радиус из той же точки кастомизации, что и сама кнопка, — --gr-button-radius (по умолчанию 0.375rem). Задайте её один раз, и края группы поедут вместе с кнопками:

css
.app { --gr-button-radius: 12px; }
Доступность

Корень объявлен role="group"; имя задаётся пропом ariaLabel — без него набор кнопок читается как несвязанный. Кнопка под курсором или с фокусом поднимается над соседями, поэтому фокус-кольцо не срезается наложением границ.