PlHoverCard
링크 뒤에 무엇이 있는지 미리 보여 주는 카드입니다. 포인터가 그 위에 머물면 열립니다. 지나가는 길의 모든 링크에서 튀어나오지 않을 만큼 늦게 열리고, 손이 닿을 수 있을 만큼 천천히 닫힙니다.
import { PlHoverCard, PlTextLink } from 'plass-ui';
<PlHoverCard
title="Ada Lovelace"
description="Mathematician, 1815–1852"
trigger={<PlTextLink href="/ada">Ada Lovelace</PlTextLink>}
>
Wrote the first algorithm intended to be carried out by a machine.
</PlHoverCard>;import 'package:plass_ui/plass_ui.dart';
PlHoverCard(
title: const Text('Ada Lovelace'),
description: const Text('Mathematician, 1815–1852'),
trigger: PlTextLink(onPressed: open, child: const Text('Ada Lovelace')),
child: const Text('Wrote the first algorithm intended to be carried out by a machine.'),
);Props
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| trigger * | ReactElement | — | 카드가 미리 보여 주는 대상. 보통 링크이고, 감싸지 않고 그대로 렌더링됩니다 |
| title · description | ReactNode | — | 제목과 그 아래 한 줄 |
| children | ReactNode | — | 본문 |
| side | 'top' | 'right' | 'bottom' | 'left' | 'bottom' | 트리거의 어느 모서리에 나타날지. 자리가 없으면 반대쪽으로 뒤집힙니다 |
| align | 'start' | 'center' | 'end' | 'center' | 그 모서리를 따라 어디에 놓일지 |
| sideOffset · alignOffset | number | 8 · 0 | 트리거에서 떨어진 거리와 모서리를 따라 밀린 거리, 픽셀 |
| delay | number | 600 | 열리기까지 포인터가 머물러야 하는 시간(ms). 지나가는 길의 모든 링크에서 열리지 않도록 깁니다 |
| closeDelay | number | 300 | 포인터가 떠난 뒤 기다리는 시간(ms). 0일 수 없습니다 — 트리거와 카드 사이의 틈에는 포인터가 없습니다 |
| arrow | boolean | false | 트리거를 가리키는 작은 쐐기를 그립니다 |
| open · defaultOpen · onOpenChange | boolean · boolean · (open) => void | — | 바깥에서 여닫기. 주지 않으면 포인터와 키보드에 맡깁니다 |
| width | number | string | — | size가 정하는 최대 너비를 덮어씁니다 |
| size공통 | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | 시트의 타입 스케일과 radius와 패딩 |
| color공통 | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'primary' | 안쪽이 쓰는 색 역할 |
| density공통 | 'default' | 'compact' | 'default' | 시트가 내용을 얼마나 촘촘히 담을지 |
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| trigger * | Widget | — | 카드가 미리 보여 주는 대상. 보통 링크이고, 감싸지 않고 그대로 렌더링됩니다 |
| title · description | Widget? | — | 제목과 그 아래 한 줄 |
| child | Widget? | — | 본문 |
| side | PlassSide | PlassSide.bottom | 트리거의 어느 모서리에 나타날지. 자리가 없으면 반대쪽으로 뒤집힙니다 |
| align | PlassAlign | PlassAlign.center | 그 모서리를 따라 어디에 놓일지 |
| offset | double | 8 | 트리거에서 떨어진 거리와 모서리를 따라 밀린 거리, 픽셀 |
| delay | Duration | 600ms | 열리기까지 포인터가 머물러야 하는 시간(ms). 지나가는 길의 모든 링크에서 열리지 않도록 깁니다 |
| closeDelay | Duration | 300ms | 포인터가 떠난 뒤 기다리는 시간(ms). 0일 수 없습니다 — 트리거와 카드 사이의 틈에는 포인터가 없습니다 |
| arrow | bool | false | 트리거를 가리키는 작은 쐐기를 그립니다 |
| open · onOpenChanged | bool? · ValueChanged<bool>? | — | 바깥에서 여닫기. 주지 않으면 포인터와 키보드에 맡깁니다 |
| disabled | bool | false | 트리거를 비활성화하지 않으면서 카드만 열리지 않게 합니다 |
| width | double? | — | size가 정하는 최대 너비를 덮어씁니다 |
| size공통 | PlassSize | PlassSize.md | 시트의 타입 스케일과 radius와 패딩 |
| color공통 | PlassColor | PlassColor.primary | 안쪽이 쓰는 색 역할 |
| density공통 | PlassDensity | PlassDensity.standard | 시트가 내용을 얼마나 촘촘히 담을지 |
라이브러리 전체에서 공유 축이 무엇을 뜻하는지는 prop 규약에 있습니다.
Hover card, 툴팁, popover 중 고르기
셋이 있고, 구분하는 것은 무엇이 여는가와 열린 뒤에 무엇을 할 수 있는가입니다. 생김새가 아닙니다. 셋 다 같은 시트입니다.
| 여는 것 | 열린 뒤 | |
|---|---|---|
PlTooltip | 위에 머무르기 | 한 구절뿐이고 안의 어떤 것에도 닿을 수 없습니다 |
PlHoverCard | 위에 머무르기 | 포인터가 안으로 들어갈 수 있고, 제목·그림·수치가 들어갑니다 |
PlPopover | 누르기 | 닫을 때까지 남고, 입력도 받습니다 |
여기에만 있는 것은 없어야 합니다
이 컴포넌트가 맞는 선택인지를 정하는 규칙입니다.
hover로 열리는 카드는 손가락으로는 열리지 않습니다. 페이지의 다른 어디에도 없는 링크나 버튼이나 사실은, 터치로 읽는 사람 모두가 놓치는 링크·버튼·사실입니다. 그래서 안에 있는 것은 전부 이미 닿을 수 있는 무언가의 미리 보기입니다. 트리거가 가는 페이지, 자기 화면이 붙은 프로필, 아래 표에 다시 나오는 수치.
그래서 애초에 안전하고, 그래서 닫기 버튼도 포커스 가둠도 스크롤 잠금도 필요 없습니다. 끝까지 보지 못해도 잃는 것이 없습니다.
지연
delay는 600ms이고 일부러 깁니다. 포인터가 링크를 스치는 순간 열리는 카드는 다른 곳으로 가는 길에 지나치는 모든 링크에서 열립니다. 그러면 글이 있는 페이지가 움찔거리는 페이지가 됩니다.
closeDelay는 300ms이고 0일 수 없습니다. 트리거와 카드 사이의 틈에는 포인터가 없으므로, 트리거를 벗어나는 순간 닫히는 카드에는 영영 닿을 수 없습니다. 그리고 거기에 닿을 수 있다는 것이 tooltip과의 차이 전부입니다.
링크가 전부 미리 보기인 페이지(사람 목록, 이슈 목록) 에서만 delay를 줄이고, 나머지에서는 그대로 두십시오.
Examples
사람
흔한 경우이고, 이 컴포넌트가 그려진 모양입니다.
<PlHoverCard
title="Ada Lovelace"
description="Mathematician"
trigger={<PlTextLink href="/people/ada">Ada Lovelace</PlTextLink>}
>
<div className="flex items-center gap-3">
<PlAvatar name="Ada Lovelace" />
<p>Wrote the first algorithm intended for a machine.</p>
</div>
</PlHoverCard>링크 아래가 아닌 자리
side, align과 두 offset은 popover가 받는 것과 같은 넷이고, 자리가 없으면 반대쪽으로 뒤집힙니다.
<PlHoverCard side="right" align="start" arrow trigger={…}>…</PlHoverCard>Notes
- 트리거는 감싸는 것이 아니라 그대로 렌더링됩니다. 링크는 링크로 남아
href와 스타일과 tab 순서를 유지하고, 카드는 레이아웃에 상자를 더하지 않습니다. - 시트는 popover가 그리는 것과 같은 서리 낀 패널이고,
size단계마다 한 칸씩 넓습니다. popover는 컨트롤 옆의 세부 사항이고, 힌트 폭으로 눌린 미리 보기는 아무도 읽지 않습니다. arrow는 popover와 마찬가지로 기본이 꺼짐입니다. 시트는 흐려진 배경 위의 반투명이고, 자기 상자 밖으로 튀어나온 쐐기는 그 배경을 함께 가져가지 못합니다.
- Base UI의
PreviewCard가 앵커링, 창 가장자리에서의 뒤집기, 두 지연, 닫기를 가집니다.
- 포인터를 트리거와 카드 양쪽에서 따라가고, 플래그가 하나가 아니라 둘입니다. 그래서 둘 사이의 틈을 건널 수 있습니다.
- 위에
Overlay가 필요합니다. navigator가 있는WidgetsApp과MaterialApp둘 다 제공합니다.
Accessibility
- hover뿐 아니라 키보드 포커스에서도 열립니다. 링크가 이어진 문단을 tab으로 지나가는 사람도 포인터와 같은 미리 보기를 받습니다. hover만 받는 카드가 잃는 절반이고, 여기서는 공짜입니다.
- Escape로 닫힙니다.
- dialog가 아니고 포커스를 가져가지 않습니다. 안에 있는 것은 포인터로 닿을 수 있고, 위의 규칙대로 포인터 없이도 닿을 수 있어야 합니다.
- 트리거는 원래 가지고 있던 role을 그대로 유지합니다. 카드를 여는 링크도 여전히 링크이고, 말한 곳으로 갑니다.