GrChipGroup

  • ядро
  • Данные
  • API · 13 props
  • ⌨ клавиши

Берут, когда фильтры списка строкой.

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

Обзор

Когда брать

  • фильтры списка строкой — статусы, категории, метки: видно все варианты сразу, выбранных может быть несколько;
  • выбор из коротких вариантов вместо списка — период отчёта, приоритет: вариантов до десятка, и прятать их под кнопку незачем;
  • набор меток записи, который правят на месте — closable даёт крестик каждому чипу, а Delete снимает тот, что под фокусом;
  • поле формы, где значение — набор — группа читает контекст GrFormField и отдаёт значение в нативную форму по name.

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

НужноБерите
Один выбор, вариантов немного, вид переключателяGrSegmented
Один выбор с описаниями у вариантовGrRadioGroup
Множественный выбор списком с отметкамиGrCheckboxGroup
Вариантов десятки, их ищут вводомGrSelect / GrAutocomplete
Ряд снимаемых меток без выбораGrChip без группы

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

Варианты · GrChipGroup
tone \ darkfalsetrue
primary
neutral
success
warning
danger
info
slate
azure

Размеры

  • xs
  • sm
  • md
  • lg

Состояния

  • обычная
  • disabled
  • readonly
  • invalid

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

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

Сцена

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

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

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

  • Фильтры каталога: несколько и один

    Комнаты и материалы сочетаются, поэтому их группы держат массив — это listbox с одной остановкой Tab и стрелками внутри. Доставка — одно из двух или любая: selection="single" делает radiogroup, а повторный клик по выбранному чипу сбрасывает значение в null, и страница читает его как «любой срок».

    Room
    Material
    Delivery
    3 desks · any delivery date
    • Halden desk
    • Brekka standing desk
    • Lune vanity
    • Orsa writing desk
    • Tove kids desk
    • Kalla corner desk
  • Приоритет в форме заявки

    У каждого приоритета свой смысл, поэтому у каждого чипа свой tone. Внутри GrFormField группа берёт подпись и обязательность у поля, а name кладёт значение в нативную форму — отправьте её и посмотрите на данные.

    New ticketCard declined on renewal · Northwind Traders
    form data appears here
  • Не больше трёх выделенных

    Группа не ограничивает выбор: предел — правило приложения, поэтому приложение и отказывает в четвёртом выборе, и объясняет почему. closable даёт каждому чипу крестик с его именем, Delete снимает чип под фокусом, а remove — только просьба: навык из списка убирает страница.

    SkillsPick up to three to highlight · Delete removes the focused one
    1 highlight left
  • Первый вопрос после регистрации

    size="lg" и radius="round" дают ряд, по которому легко попасть с телефона; группа раздаёт tone всем чипам, а выбранный берёт плотную заливку того же оттенка. Недоступный чип остаётся читаемым, поэтому «Payroll · soon» видно, а не пропущено.

    What will you use Acme Billing for?Pick all that apply — we will set up the workspace around them

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

Props

PropTypeпо умолчаниюОписание
disabledboolean | undefinedfalseНабор недоступен: чипы не выбираются и не снимаются. Включается и от `GrFormField`.
tone
"primary" | "neutral" | "success" | "warning" | "danger" | ""primary" | "neutral" | "success" | "warning" | "danger" | "info" | "slate" | "azure" | undefined
undefinedТон всех чипов набора; проп чипа сильнее. Не задан — `GrConfigProvider`, иначе `neutral`.
closableboolean | undefinedfalseКрестик у всех чипов набора. Точечно перебивается пропом самого чипа.
modelValuev-modelGrChipValue | GrChipValue[] | null | undefinedundefinedОдиночный выбор — значение, множественный — массив.
readonlyboolean | undefinedfalseВыбор видно, но он не меняется.
invalidboolean | undefinedfalseЗначение с ошибкой: `aria-invalid` на группе. Включается и от ошибки `GrFormField`.
requiredboolean | undefinedfalseВыбор обязателен: `aria-required` на группе. Включается и от `GrFormField`.
size"xs" | "sm" | "md" | "lg" | undefinedundefinedСтупень шкалы для всех чипов набора; проп чипа сильнее. По умолчанию `md`.
ariaLabelstring | undefinedundefinedДоступное имя набора. Внутри `GrFormField` не нужно: группу именует подпись поля.
namestring | undefinedundefinedИмя для нативной формы. Множественный выбор отдаёт по полю на значение.
darkboolean | undefinedundefinedЗаливка тоном вместо мягкой подложки у всех чипов набора; проп чипа сильнее.
radiusGrBadgeRadius | undefinedundefinedФорма всех чипов набора: `round`, `semi` или `square`; проп чипа сильнее.
selectionGrChipSelection | undefined"multiple"Множественность выбора: `multiple` — массив значений и роль `listbox`, `single` — одно значение или `null` и роль `radiogroup`. По умолчанию `multiple`.

Слоты

SlotTypeОписание
defaultanyЧипы набора.

События

EventСигнатураОписание
update:modelValue(event: "update:modelValue", value: GrChipValue | GrChipValue[] | null): void—
change(event: "change", value: GrChipValue | GrChipValue[] | null): void—
focus(event: "focus", event: FocusEvent): void—
blur(event: "blur", event: FocusEvent): void—
remove(event: "remove", value: GrChipValue): void—

Методы

MethodsСигнатураОписание
focus() => void | undefinedФокус на активный чип — тот, что держит остановку `Tab` набора.
blur() => void | undefinedСнять фокус с активного чипа набора.

Типы

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

Импорт
import type { GrChipGroupConfigurableProps, GrChipGroupProps, GrChipGroupEmits } from '@feugene/granularity/components/GrChipGroup'

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

grChipGroupConfigconst
const grChipGroupConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrChipGroup">;

Файлdist/types/components/GrChipGroup/defaults.d.ts

GrChipGroupConfigurablePropsinterface

Пропы GrChipGroup, настраиваемые глобально через componentDefaults. Размер группы доезжает до чипов контекстом — задавать его на каждом не нужно.

interface GrChipGroupConfigurableProps {
    size: GrChipSize;
}

Файлdist/types/components/GrChipGroup/safelist.d.ts

grChipGroupSafelistconst
const grChipGroupSafelist: string[];

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

GrChipGroupPropsinterface

GrChipGroup — набор выбираемых чипов: фильтры, теги записи, быстрый выбор. Составной виджет: одна остановка Tab, внутрь попадают стрелками (roving tabindex). Роль зависит от множественности выбора — radiogroup в одиночном, listbox с aria-multiselectable во множественном; чипы получают парную роль через контекст и сами её не выбирают. Состав группа не рисует: чипы приходят слотом, потому что у каждого своя подпись и иконка. Отсюда же и remove — группа его ретранслирует, а снимает чип потребитель, у которого лежит массив.

interface GrChipGroupProps {
    /** Одиночный выбор — значение, множественный — массив. */
    modelValue?: GrChipValue | GrChipValue[] | null;
    /**
     * Множественность выбора: `multiple` — массив значений и роль `listbox`, `single` — одно
     * значение или `null` и роль `radiogroup`. По умолчанию `multiple`.
     */
    selection?: GrChipSelection;
    /** Имя для нативной формы. Множественный выбор отдаёт по полю на значение. */
    name?: string;
    /** Набор недоступен: чипы не выбираются и не снимаются. Включается и от `GrFormField`. */
    disabled?: boolean;
    /** Выбор видно, но он не меняется. */
    readonly?: boolean;
    /** Значение с ошибкой: `aria-invalid` на группе. Включается и от ошибки `GrFormField`. */
    invalid?: boolean;
    /** Выбор обязателен: `aria-required` на группе. Включается и от `GrFormField`. */
    required?: boolean;
    /** Крестик у всех чипов набора. Точечно перебивается пропом самого чипа. */
    closable?: boolean;
    /** Ступень шкалы для всех чипов набора; проп чипа сильнее. По умолчанию `md`. */
    size?: GrChipSize;
    /** Тон всех чипов набора; проп чипа сильнее. Не задан — `GrConfigProvider`, иначе `neutral`. */
    tone?: GrChipTone;
    /** Форма всех чипов набора: `round`, `semi` или `square`; проп чипа сильнее. */
    radius?: GrChipRadius;
    /** Заливка тоном вместо мягкой подложки у всех чипов набора; проп чипа сильнее. */
    dark?: boolean;
    /** Доступное имя набора. Внутри `GrFormField` не нужно: группу именует подпись поля. */
    ariaLabel?: string;
}
GrChipGroupEmitsinterface
interface GrChipGroupEmits {
    /** Новое значение (`v-model`): массив в `multiple`, значение или `null` в `single`. */
    (e: 'update:modelValue', value: GrChipValue | GrChipValue[] | null): void;
    /** Пользователь изменил выбор кликом или клавишей; приходит вместе с `update:modelValue`. */
    (e: 'change', value: GrChipValue | GrChipValue[] | null): void;
    /**
     * Чип просят снять — крестиком или `Delete`. Группа его не убирает: значение удаляет из
     * массива потребитель.
     */
    (e: 'remove', value: GrChipValue): void;
    /** Фокус вошёл в набор. Переходы между чипами стрелками событием не считаются. */
    (e: 'focus', event: FocusEvent): void;
    /** Фокус ушёл из набора целиком. */
    (e: 'blur', event: FocusEvent): void;
}

Файлdist/types/components/GrChipGroup/index.d.ts

GrChipGroupInstancetype
type GrChipGroupInstance = ComponentExposed<typeof GrChipGroupComponent>;

Доступность

Паттерн APG

listbox / radiogroup (roving tabindex)

Клавиши

Home / EndDelete / Backspace

КлавишаДействие
—Набор — одна остановка Tab, внутрь ведут стрелки по обеим осям (чипы переносятся на новую строку)
Home / Endк краям
Delete / Backspaceснять чип под фокусом. **Стрелка двигает только фокус, даже в одиночном режиме**: у чипа есть второе действие, и менять значение по дороге к нужному чипу нельзя

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

Роль зависит от множественности выбора

selection="multiple" (по умолчанию) объявляет группу listbox с aria-multiselectable, а чипы — option с aria-selected. selection="single" — radiogroup и radio с aria-checked, как у GrSegmented.

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

Одна остановка Tab, внутрь — стрелками

Группа составная, поэтому занимает одну остановку в таб-порядке: активный чип держит tabindex="0", остальные -1. Стрелки работают по обеим осям — чипы переносятся на новую строку, и «вниз» означает следующий чип так же, как «вправо». Home/End уводят к краям.

Стрелка двигает только фокус, даже в одиночном режиме. У чипов есть второе действие — снятие по Delete, — и переносить выбор вместе с фокусом значило бы менять модель при попытке дойти до нужного чипа. В radiogroup формы принято обратное, но там у элементов одного действия.

Повторный выбор снимает отметку

В одиночном режиме клик по уже выбранному чипу сбрасывает значение в null. Набор фильтров без выбранного значения осмыслен («любой»), и отменить выбор иначе было бы нечем — в отличие от переключателей формы, где пустое значение обычно запрещено.

Состав рисует потребитель

Пропа options у группы нет: у каждого чипа своя подпись, иконка и тон, и генерировать их из плоского массива значило бы завести второй, более бедный способ описать то же самое. Отсюда же remove — группа его только ретранслирует, а убирает элемент из массива приложение.

Границы
  • своего порядка у группы нет — она рисует чипы в порядке слота;
  • группа не ограничивает число выбранных. Предел — правило приложения, и сообщение о нём тоже: группа не знает, что показать вместо отказа;
  • вложенных групп не бывает. Набор внутри набора даёт неразрешимый вопрос, чья стрелка обрабатывается.