GrTooltip

  • ядро
  • Навигация
  • API · 11 props
  • ⌨ клавиши

Берут, когда подпись к иконочной кнопке.

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

Обзор

Когда брать

  • подпись к иконочной кнопке — единственный способ дать имя контролу, у которого нет видимого текста;
  • расшифровка сокращения или статуса — короткий текст, который иначе занял бы место в раскладке;
  • подсказка появляется и по фокусу — не только по наведению, поэтому она достижима с клавиатуры;
  • текста немного — одна-две строки: длинный текст в подсказке нельзя ни выделить, ни прокрутить.

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

НужноБерите
Внутри нужен интерактив: ссылка, кнопка, полеGrPopover
Список действийGrDropdownMenu
Сообщение, которое пользователь обязан заметитьGrAlert
Сообщение о результате действияGrToaster
Постоянное пояснение под полемGrFormField

Единственным носителем информации подсказка быть не может. На тач-устройстве наведения нет, а текст, доступный только по нему, для части пользователей не существует вовсе. То, без чего задачу не выполнить, живёт в самой раскладке — подписью, хинтом поля или строкой рядом.

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

Сцена

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

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

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

  • Кнопки-иконки, которые называют себя

    Слот по умолчанию принимает триггер, и кнопка внутри — единственная остановка Tab. Имя у неё своё — aria-label, сочетание — aria-keyshortcuts, поэтому подсказка — те же слова с клавишами для глаз, через слот content, — второй раз не читается: describe-trigger выключен. open-delay не даёт подсказкам мигать, пока курсор бежит по ряду.

    Note on the invoice

    Thank you for your business. Payment within 30 days to IE29 AIBK 9311 5212 3456 78.

  • Термины в сравнении тарифов

    Без своего триггера подсказка рисует иконку info и сама становится остановкой Tab; text — всё пояснение. placement="top-start" поднимает её над строкой, и цены, которые она поясняет, остаются на виду, size="sm" подгоняет под таблицу, а icon-color — под приглушённый текст рядом. Цифры остаются в таблице: подсказка не может быть единственным носителем — на сенсорном экране наведения нет.

    PlanTeam · €49Business · €149
    Seats 1050
    Overage €0.20 each€0.10 each
    SSO —Included
  • Длинные имена в узкой колонке

    Каждая строка — триггер, поэтому block растягивает обёртку на строку. Подсказку получает только имя, обрезанное многоточием, у остальных она disabled: повтор видимого текста — шум. «Where is the export?» открывает подсказку кнопки выгрузки на несколько секунд через v-model:open, а offset-px держит её на расстоянии от кнопки.

    Customers
    • Northwind Traders
    • Fabrikam Industrielle Fertigung und Vertrieb GmbH & Co. KG
    • Contoso Ltd
    • Adventure Works Cycles Manufacturing and Distribution, S.L.

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

Props

PropTypeпо умолчаниюОписание
placementPlacement | undefined"top"Предпочтительная сторона панели; `flip` может её изменить.
disabledboolean | undefinedfalseПодсказка не показывается ничем — ни курсором, ни фокусом, ни `v-model:open`.
openv-modelboolean | undefinedundefinedУправляемая видимость. Без неё компонент ведёт видимость сам.
size"xs" | "sm" | "md" | "lg" | undefinedundefinedРазмер панели и дефолтной триггер-иконки.
blockboolean | undefinedfalseОбёртка занимает ширину родителя вместо ширины содержимого. Нужно там, где триггер обязан тянуться: пункт списка, строка меню, ячейка. `inline-flex` по умолчанию схлопнул бы такой триггер по содержимому, и подсветка с кольцом фокуса сжались бы вместе с ним.
offsetPxnumber | undefinedundefinedЗазор между триггером и панелью, px.
openDelaynumber | undefined0Задержка перед показом, мс. Спасает от мигания при проведении курсором по панели кнопок.
closeDelaynumber | undefined0Задержка перед скрытием, мс.
textstring | undefinedundefinedТекст подсказки. Разметка вместо текста — слот `#content`.
iconColorstring | undefined"var(--gr-muted-fg)"Цвет триггер-иконки (CSS color). По умолчанию — `var(--gr-muted-fg)`.
describeTriggerboolean | undefinedtrueВешать ли `aria-describedby` на триггер. По умолчанию да. `false` — когда подсказка **дословно повторяет** доступное имя триггера: тогда это не описание, а шум, и диктор произносит подпись дважды. Так устроен свёрнутый `GrSidebarItem`: имя у него уже в `aria-label`.

Слоты

SlotTypeОписание
defaultanyТриггер. По умолчанию — иконка info.
contentanyСодержимое подсказки; заменяет проп `text`.

События

EventСигнатураОписание
update:open(event: "update:open", value: boolean): void—

Типы

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

Импорт
import type { GrTooltipPlacement, GrTooltipProps, GrTooltipEmits } from '@feugene/granularity/components/GrTooltip'

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

GrTooltipPlacementtype
type GrTooltipPlacement = UseFloatingPlacement;
GrTooltipPropsinterface
interface GrTooltipProps {
    /** Текст подсказки. Разметка вместо текста — слот `#content`. */
    text?: string;
    /** Цвет триггер-иконки (CSS color). По умолчанию — `var(--gr-muted-fg)`. */
    iconColor?: string;
    /** Размер панели и дефолтной триггер-иконки. */
    size?: GrTooltipSize;
    /** Предпочтительная сторона панели; `flip` может её изменить. */
    placement?: GrTooltipPlacement;
    /** Зазор между триггером и панелью, px. */
    offsetPx?: number;
    /** Задержка перед показом, мс. Спасает от мигания при проведении курсором по панели кнопок. */
    openDelay?: number;
    /** Задержка перед скрытием, мс. */
    closeDelay?: number;
    /** Подсказка не показывается ничем — ни курсором, ни фокусом, ни `v-model:open`. */
    disabled?: boolean;
    /** Управляемая видимость. Без неё компонент ведёт видимость сам. */
    open?: boolean;
    /**
     * Обёртка занимает ширину родителя вместо ширины содержимого.
     *
     * Нужно там, где триггер обязан тянуться: пункт списка, строка меню, ячейка.
     * `inline-flex` по умолчанию схлопнул бы такой триггер по содержимому, и
     * подсветка с кольцом фокуса сжались бы вместе с ним.
     */
    block?: boolean;
    /**
     * Вешать ли `aria-describedby` на триггер. По умолчанию да.
     *
     * `false` — когда подсказка **дословно повторяет** доступное имя триггера:
     * тогда это не описание, а шум, и диктор произносит подпись дважды. Так
     * устроен свёрнутый `GrSidebarItem`: имя у него уже в `aria-label`.
     */
    describeTrigger?: boolean;
}
GrTooltipEmitsinterface
interface GrTooltipEmits {
    /** Подсказка показана или скрыта (`v-model:open`): курсором, фокусом, тапом или `Esc`. */
    (e: 'update:open', value: boolean): void;
}

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

grTooltipConfigconst
const grTooltipConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrTooltip">;

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

GrTooltipConfigurablePropsinterface

Пропы GrTooltip, настраиваемые глобально через componentDefaults.

interface GrTooltipConfigurableProps {
    size: GrComponentSize;
}

Файлdist/types/components/GrTooltip/grTooltipStyles.d.ts

GrTooltipSizetype
type GrTooltipSize = GrComponentSize;

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

grTooltipSafelistconst
const grTooltipSafelist: string[];

Доступность

Клавиши

Esc

КлавишаДействие
Escскрыть (мгновенно, минуя closeDelay); показывается по фокусу триггера, не только по наведению. Со слотом остановка Tab одна — сам контрол, а описание уезжает на него

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

Триггер и таб-порядок

Без слота триггер — иконка info, и остановкой Tab становится обёртка. Со слотом обёртка отходит в сторону: если внутри есть фокусируемый элемент (кнопка, ссылка, поле), aria-describedby уезжает на него, а обёртка теряет tabindex. Иначе на один визуальный контрол приходилось бы два таб-стопа, причём внешний — безролевой <span>.

Если фокусироваться в слоте нечему (текст, картинка), обёртка остаётся остановкой Tab — иначе подсказка была бы недоступна с клавиатуры вовсе. Но только пока подсказку есть что показать: с disabled (или без текста) обёртка снимает и tabindex, и aria-describedby. Типичный случай — подсказка с полным текстом, включённая только у обрезанной строки списка: остальные строки лишних остановок не дают.

describe-trigger="false" отменяет aria-describedby. Нужно там, где подсказка дословно повторяет доступное имя триггера: описание тем же текстом диктор прочитает вторым заходом, и получится «Billing, Billing». Так подключён свёрнутый GrSidebarItem — имя ему даёт aria-label, а подсказка нужна глазам.

vue
<!-- Обёртка прозрачна: остановка Tab одна — сама кнопка. -->
<GrTooltip text="Удалить безвозвратно">
  <GrButton variant="ghost" square><IconTrash /></GrButton>
</GrTooltip>
Содержимое

text — короткая строка; разметка вместо неё — слот #content. Без того и другого подсказка не открывается: пустая панель хуже отсутствующей.

Ширина триггера

Обе обёртки — внешняя и триггерная — по умолчанию inline-flex, то есть подсказка сжимается по содержимому. block переводит их в flex w-full: нужно, когда триггер обязан занять ширину родителя — пункт списка, строка меню, ячейка. Проп меняет обе обёртки: снаружи до внутренней класс не доходит, и одной внешней мало — триггер всё равно схлопнулся бы вместе с подсветкой и кольцом фокуса. Содержимое такого триггера прижато к началу, как строка списка, а не к центру.

Размещение

placement — любая сторона из шкалы @floating-ui (top, right-start, …), offsetPx — зазор до триггера. Итоговая сторона может отличаться от заданной: flip переворачивает подсказку, когда места не хватает, shift не даёт ей вылезти за край экрана.

Задержки

openDelay и closeDelay (мс, по умолчанию оба 0). Задержка показа нужна там, где подсказки стоят плотно — на панели кнопок без неё подсказка мигает при каждом проведении курсором. Escape и клик вне закрывают мгновенно, минуя closeDelay: задержка там читалась бы как залипание.

Управление снаружи

disabled запрещает показ полностью. v-model:open переводит видимость под контроль владельца — компонент перестаёт открывать себя сам и только сообщает о намерении через update:open.

Тач

На тач-устройствах hover не существует, а фокус по тапу не гарантирован, поэтому тап по триггеру переключает подсказку, а тап вне — закрывает.