Popover
Панель с произвольным содержимым, привязанная к элементу, — карточка внутри попапа, ровно как и записано в комментарии к .aura-popup. От тултипа отличается не формой, а тем, что с ней можно делать: тултип это подпись, он закрывается при уходе указателя, а поповер держит то, с чем взаимодействуют, поэтому открывается по клику, сохраняет фокус и закрывается по Escape или клику снаружи. Привязка — единственное, что каждый пакет пишет по-своему: React клонирует элемент триггера, Vue — vnode, Svelte отдаёт триггеру пропсы для раскрытия, Angular — директива, принимающая панель как шаблон. Ни один не добавляет элемента: обёртка портировалась бы всюду и встала бы между триггером и его раскладкой.
Anything can go here.
Код
<button type="button" class="aura-btn aura-btn--secondary"
aria-haspopup="dialog" aria-expanded="true" aria-controls="p1">Filters</button>
<div id="p1" role="dialog" aria-label="Filters" data-state="open" class="aura-popup aura-popover aura-card">
<p class="aura-text aura-text--body">Anything can go here.</p>
</div>import { Button, Popover, Stack, Typography } from '@ilomee/aura-react';
/**
* Нажмите на триггер. Панель портализуется в `document.body` и позиционируется через `place()`: она
* переворачивается, когда не влезает, и следует за прокруткой, а закрывается по Escape или по
* нажатию где угодно, кроме себя и триггера.
*/
export default function Demo() {
return (
<Popover
label="Filters"
content={
<Stack gap={2}>
<Typography variant="h3">Filters</Typography>
<Typography variant="body" tone="muted">
Anything can go here — a popover holds things to interact with, which is the half a
tooltip cannot have.
</Typography>
</Stack>
}
>
<Button variant="secondary">Filters</Button>
</Popover>
);
}<script setup lang="ts">
import { Popover, Button } from '@ilomee/aura-vue';
</script>
<template>
<Popover label="Filters">
<template #content><p>Anything can go here.</p></template>
<Button variant="secondary">Filters</Button>
</Popover>
</template><script lang="ts">
import { Popover } from '@ilomee/aura-svelte';
</script>
<Popover label="Filters">
{#snippet trigger(props)}
<button type="button" class="aura-btn aura-btn--secondary" {...props}>Filters</button>
{/snippet}
<p>Anything can go here.</p>
</Popover>Используется как [auraPopover] — директива, которую вы вешаете на свой элемент.
<button auraButton variant="secondary" [auraPopover]="panel" label="Filters">Filters</button>
<ng-template #panel><p auraText>Anything can go here.</p></ng-template>Директива снимает собственный атрибут auraPopover в ngOnInit, поэтому итоговый триггер совпадает с остальными тремя.
Пропсы
| Имя | Тип | По умолчанию | Примечания |
|---|---|---|---|
| content* | ReactNode | — | Содержимое панели. Что угодно — та половина, которой у тултипа быть не может. |
| children* | ReactElement | — | Открывающий контрол. Клонируется, а не оборачивается. |
| label | string | — | Доступное имя панели. Диалог без имени объявляется как группа без подписи: читателю сообщают, что нечто открылось, но не что именно. |
| openOn | 'click' | 'hover' | 'click' | Чем открывается. hover реагирует и на указатель, и на фокус, а закрывается через момент после того, как оба ушли и с триггера, и с панели: панель телепортируется в <body> и отстоит от триггера, поэтому указатель идёт к ней по голой странице, и закрытие по первому pointerleave сделало бы панель недостижимой тем самым жестом, которым её открыли. Клик продолжает переключать — на тач-устройстве ховера нет. Панель в режиме hover не запирает фокус, в отличие от click: ловушка уместна там, где панель попросили, и враждебна там, где она появилась под указателем. Escape и клик снаружи закрывают её по-прежнему. |
| openдвусторонний | boolean | — | |
| defaultOpen | boolean | false | |
| onOpenChangeсобытие | (open: boolean) => void | — | |
| side | 'top' | 'right' | 'bottom' | 'left' | 'bottom' | |
| align | 'start' | 'center' | 'end' | 'start' |
| Имя | Тип | По умолчанию | Примечания |
|---|---|---|---|
| defaultслот | slot | — | Триггер. Ровно один элемент, клонируется. |
| contentслот | slot | — | Содержимое панели. |
| label | string | — | |
| openOn | 'click' | 'hover' | 'click' | Чем открывается. hover реагирует и на указатель, и на фокус, а закрывается через момент после того, как оба ушли и с триггера, и с панели: панель телепортируется в <body> и отстоит от триггера, поэтому указатель идёт к ней по голой странице, и закрытие по первому pointerleave сделало бы панель недостижимой тем самым жестом, которым её открыли. Клик продолжает переключать — на тач-устройстве ховера нет. Панель в режиме hover не запирает фокус, в отличие от click: ловушка уместна там, где панель попросили, и враждебна там, где она появилась под указателем. Escape и клик снаружи закрывают её по-прежнему. |
| openдвусторонний | boolean | — | |
| update:openсобытие | (open: boolean) => void | — | |
| side | 'top' | 'right' | 'bottom' | 'left' | 'bottom' | |
| align | 'start' | 'center' | 'end' | 'start' |
| Имя | Тип | По умолчанию | Примечания |
|---|---|---|---|
| trigger* | Snippet<[TriggerProps]> | — | Получает пропсы для раскрытия на контроле. Клонирования в Svelte нет, и именно раскрытие избавляет разметку от обёртки. |
| children* | Snippet | — | Содержимое панели. |
| label | string | — | |
| openOn | 'click' | 'hover' | 'click' | Чем открывается. hover реагирует и на указатель, и на фокус, а закрывается через момент после того, как оба ушли и с триггера, и с панели: панель телепортируется в <body> и отстоит от триггера, поэтому указатель идёт к ней по голой странице, и закрытие по первому pointerleave сделало бы панель недостижимой тем самым жестом, которым её открыли. Клик продолжает переключать — на тач-устройстве ховера нет. Панель в режиме hover не запирает фокус, в отличие от click: ловушка уместна там, где панель попросили, и враждебна там, где она появилась под указателем. Escape и клик снаружи закрывают её по-прежнему. |
| openдвусторонний | boolean | — | |
| side | 'top' | 'right' | 'bottom' | 'left' | 'bottom' | |
| align | 'start' | 'center' | 'end' | 'start' |
| Имя | Тип | По умолчанию | Примечания |
|---|---|---|---|
| auraPopover* | TemplateRef | — | Содержимое панели в виде шаблона. <ng-template> сам по себе ничего не рендерит — именно поэтому разметка совпадает с остальными тремя. |
| label | string | — | |
| openOn | 'click' | 'hover' | 'click' | Чем открывается. hover реагирует и на указатель, и на фокус, а закрывается через момент после того, как оба ушли и с триггера, и с панели: панель телепортируется в <body> и отстоит от триггера, поэтому указатель идёт к ней по голой странице, и закрытие по первому pointerleave сделало бы панель недостижимой тем самым жестом, которым её открыли. Клик продолжает переключать — на тач-устройстве ховера нет. Панель в режиме hover не запирает фокус, в отличие от click: ловушка уместна там, где панель попросили, и враждебна там, где она появилась под указателем. Escape и клик снаружи закрывают её по-прежнему. |
| openдвусторонний | boolean | — | |
| openChangeсобытие | (open: boolean) => void | — | |
| side | 'top' | 'right' | 'bottom' | 'left' | 'bottom' | |
| align | 'start' | 'center' | 'end' | 'start' |
Какие классы отдаёт
Все фреймворки отдают одни и те же классы — именно поэтому четыре библиотеки выглядят одинаково. Их можно использовать напрямую, вообще без библиотеки компонентов.
| Класс | Роль | Примечания |
|---|---|---|
| .aura-popup | база | Обязательный. Без него модификатор не работает. |
| .aura-popover | база | Обязательный. Без него модификатор не работает. |
| .aura-card | база | Обязательный. Без него модификатор не работает. |
Токены и правила
components.css- слой
- var(--z-dropdown) — under a modal, on purpose
- ширина
- min(360px, calc(100vw - 16px)) — its content’s, not its anchor’s
- поверхность
- .aura-card — no block of its own