Примитивы
35

Popover

Панель с произвольным содержимым, привязанная к элементу, — карточка внутри попапа, ровно как и записано в комментарии к .aura-popup. От тултипа отличается не формой, а тем, что с ней можно делать: тултип это подпись, он закрывается при уходе указателя, а поповер держит то, с чем взаимодействуют, поэтому открывается по клику, сохраняет фокус и закрывается по Escape или клику снаружи. Привязка — единственное, что каждый пакет пишет по-своему: React клонирует элемент триггера, Vue — vnode, Svelte отдаёт триггеру пропсы для раскрытия, Angular — директива, принимающая панель как шаблон. Ни один не добавляет элемента: обёртка портировалась бы всюду и встала бы между триггером и его раскладкой.

чистая разметка — библиотеки на странице нет
отрендерил aura-react
отрендерил aura-react
отрендерил aura-react
отрендерил aura-react

Код

index.html
<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>
Demo.tsx
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>
  );
}
Demo.vue
<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>
Demo.svelte
<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] — директива, которую вы вешаете на свой элемент.

demo.component.ts
<button auraButton variant="secondary" [auraPopover]="panel" label="Filters">Filters</button>
<ng-template #panel><p auraText>Anything can go here.</p></ng-template>

Директива снимает собственный атрибут auraPopover в ngOnInit, поэтому итоговый триггер совпадает с остальными тремя.

Пропсы

У чистой разметки нет пропсов — классы ниже и есть весь API. Четыре пакета не делают ничего сверх того, что проставляют вам те же самые классы.
ИмяТипПо умолчаниюПримечания
content*ReactNodeСодержимое панели. Что угодно — та половина, которой у тултипа быть не может.
children*ReactElementОткрывающий контрол. Клонируется, а не оборачивается.
labelstringДоступное имя панели. Диалог без имени объявляется как группа без подписи: читателю сообщают, что нечто открылось, но не что именно.
openOn'click' | 'hover''click'Чем открывается. hover реагирует и на указатель, и на фокус, а закрывается через момент после того, как оба ушли и с триггера, и с панели: панель телепортируется в <body> и отстоит от триггера, поэтому указатель идёт к ней по голой странице, и закрытие по первому pointerleave сделало бы панель недостижимой тем самым жестом, которым её открыли. Клик продолжает переключать — на тач-устройстве ховера нет. Панель в режиме hover не запирает фокус, в отличие от click: ловушка уместна там, где панель попросили, и враждебна там, где она появилась под указателем. Escape и клик снаружи закрывают её по-прежнему.
openдвустороннийboolean
defaultOpenbooleanfalse
onOpenChangeсобытие(open: boolean) => void
side'top' | 'right' | 'bottom' | 'left''bottom'
align'start' | 'center' | 'end''start'
ИмяТипПо умолчаниюПримечания
defaultслотslotТриггер. Ровно один элемент, клонируется.
contentслотslotСодержимое панели.
labelstring
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Содержимое панели.
labelstring
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> сам по себе ничего не рендерит — именно поэтому разметка совпадает с остальными тремя.
labelstring
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