Popover
트리거 요소 주변에 표시되는 경량 Popover 컴포넌트입니다. 4가지 위치(top, bottom, left, right)와 3가지 정렬(start, center, end)을 지원하며, 화살표, 커스텀 색상, 바운스 애니메이션 등 다양한 옵션을 제공합니다.
미리보기
사용법
1"use client";
2
3import { Button, Popover } from "motile-ui";
4
5export default function PreviewExample() {
6 return (
7 <Popover.Root position="bottom" align="center">
8 <Popover.Trigger asChild>
9 <Button variant="primary">Open Popover</Button>
10 </Popover.Trigger>
11 <Popover.Content>
12 <h3 style={{ margin: "0 0 8px 0", fontSize: "16px", fontWeight: 600, color: "#fff" }}>
13 Popover 제목
14 </h3>
15 <p style={{ margin: 0, fontSize: "14px", color: "rgba(255, 255, 255, 0.9)", lineHeight: 1.6 }}>
16 Popover 컴포넌트입니다. ESC 키를 누르거나 외부를 클릭하여 닫을 수 있습니다.
17 </p>
18 </Popover.Content>
19 </Popover.Root>
20 );
21}API 레퍼런스
Popover.Root
Popover의 상태를 관리하는 최상위 컨텍스트 프로바이더
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
position | "top" | "bottom" | "left" | "right" | "bottom" | Popover 위치 (top, bottom, left, right) |
align | "start" | "center" | "end" | "center" | Popover 정렬 방식 (start, center, end) |
variant | "filled" | "outlined" | "filled" | Popover 스타일 variant (filled, outlined) |
showArrow | boolean | false | 화살표 표시 여부 |
zIndex | number | 10 | z-index 값 |
color | string | - | 커스텀 색상 (CSS 색상 값) |
bounceCount | number | "infinite" | 0 | 통통 튀는 애니메이션 횟수 (0이면 비활성화, 'infinite'로 무한 반복 가능) |
open | boolean | - | Popover 열림/닫힘 상태 (제어 컴포넌트) |
defaultOpen | boolean | false | 초기 열림 상태 (비제어 컴포넌트) |
onOpenChange | (open: boolean) => void | - | 상태가 변경될 때 실행되는 함수 |
autoClose | boolean | true | ESC 키와 외부 클릭으로 자동으로 닫기 |
onClickOutside | (event: PointerEvent) => void | - | 외부 클릭 시 실행되는 함수 |
onDismiss | (event: Event) => void | - | Popover가 닫힐 때 실행되는 함수 (ESC 키 또는 외부 클릭) |
Popover.Trigger
Popover를 여는 트리거 요소
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
asChild | boolean | false | 래퍼 없이 자식 요소만 렌더링 |
기본 <code>button</code> HTML 속성을 모두 사용할 수 있습니다.
Popover.Content
Popover 콘텐츠 컨테이너
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
className | string | - | CSS 클래스명 |
style | React.CSSProperties | - | 인라인 스타일 객체 |
기본 <code>div</code> HTML 속성을 모두 사용할 수 있습니다.
예제
화살표 포함
1"use client";
2
3import { Button, Popover } from "motile-ui";
4
5export default function WithArrowExample() {
6 return (
7 <Popover.Root position="top" align="center" showArrow>
8 <Popover.Trigger asChild>
9 <Button variant="secondary">With Arrow</Button>
10 </Popover.Trigger>
11 <Popover.Content>
12 <p style={{ margin: 0, fontSize: "14px", color: "rgba(255, 255, 255, 0.9)" }}>
13 화살표가 트리거 버튼을 가리킵니다.
14 </p>
15 </Popover.Content>
16 </Popover.Root>
17 );
18}다양한 위치
1"use client";
2
3import { Button, Popover } from "motile-ui";
4
5export default function PositionsExample() {
6 const positions = ["top", "bottom", "left", "right"] as const;
7
8 return (
9 <div style={{ display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: "16px" }}>
10 {positions.map((position) => (
11 <Popover.Root key={position} position={position} align="center">
12 <Popover.Trigger asChild>
13 <Button variant="secondary">
14 {position.charAt(0).toUpperCase() + position.slice(1)}
15 </Button>
16 </Popover.Trigger>
17 <Popover.Content>
18 <p style={{ margin: 0, fontSize: "14px", color: "rgba(255, 255, 255, 0.9)" }}>
19 Position: {position}
20 </p>
21 </Popover.Content>
22 </Popover.Root>
23 ))}
24 </div>
25 );
26}정렬 방식
1"use client";
2
3import { Button, Popover } from "motile-ui";
4
5export default function AlignmentsExample() {
6 const alignments = ["start", "center", "end"] as const;
7
8 return (
9 <div style={{ display: "flex", gap: "16px", flexWrap: "wrap" }}>
10 {alignments.map((align) => (
11 <Popover.Root key={align} position="top" align={align} showArrow>
12 <Popover.Trigger asChild>
13 <Button variant="secondary">
14 Align: {align.charAt(0).toUpperCase() + align.slice(1)}
15 </Button>
16 </Popover.Trigger>
17 <Popover.Content>
18 <p style={{ margin: 0, fontSize: "14px", color: "rgba(255, 255, 255, 0.9)" }}>
19 정렬 방식: <strong>{align}</strong>
20 </p>
21 </Popover.Content>
22 </Popover.Root>
23 ))}
24 </div>
25 );
26}Variant 스타일
1"use client";
2
3import { Button, Popover } from "motile-ui";
4
5export default function VariantsExample() {
6 return (
7 <div style={{ display: "flex", gap: "16px" }}>
8 <Popover.Root position="bottom" align="center" variant="filled">
9 <Popover.Trigger asChild>
10 <Button variant="primary">Filled</Button>
11 </Popover.Trigger>
12 <Popover.Content>
13 <p style={{ margin: 0, fontSize: "14px", color: "rgba(255, 255, 255, 0.9)" }}>
14 Filled 스타일입니다.
15 </p>
16 </Popover.Content>
17 </Popover.Root>
18
19 <Popover.Root position="bottom" align="center" variant="outlined">
20 <Popover.Trigger asChild>
21 <Button variant="secondary">Outlined</Button>
22 </Popover.Trigger>
23 <Popover.Content>
24 <p style={{ margin: 0, fontSize: "14px", color: "#374151" }}>
25 Outlined 스타일입니다.
26 </p>
27 </Popover.Content>
28 </Popover.Root>
29 </div>
30 );
31}커스텀 색상
1"use client";
2
3import { Button, Popover } from "motile-ui";
4
5export default function CustomColorExample() {
6 return (
7 <div style={{ display: "flex", gap: "16px", flexWrap: "wrap" }}>
8 <Popover.Root position="bottom" align="center" color="#10b981" showArrow>
9 <Popover.Trigger asChild>
10 <Button variant="secondary" color="#10b981">
11 Green
12 </Button>
13 </Popover.Trigger>
14 <Popover.Content>
15 <p style={{ margin: 0, fontSize: "14px", color: "rgba(255, 255, 255, 0.9)" }}>
16 커스텀 색상: 녹색
17 </p>
18 </Popover.Content>
19 </Popover.Root>
20
21 <Popover.Root position="bottom" align="center" color="#f59e0b" showArrow>
22 <Popover.Trigger asChild>
23 <Button variant="secondary" color="#f59e0b">
24 Orange
25 </Button>
26 </Popover.Trigger>
27 <Popover.Content>
28 <p style={{ margin: 0, fontSize: "14px", color: "rgba(255, 255, 255, 0.9)" }}>
29 커스텀 색상: 주황색
30 </p>
31 </Popover.Content>
32 </Popover.Root>
33
34 <Popover.Root position="bottom" align="center" color="#8b5cf6" showArrow>
35 <Popover.Trigger asChild>
36 <Button variant="secondary" color="#8b5cf6">
37 Purple
38 </Button>
39 </Popover.Trigger>
40 <Popover.Content>
41 <p style={{ margin: 0, fontSize: "14px", color: "rgba(255, 255, 255, 0.9)" }}>
42 커스텀 색상: 보라색
43 </p>
44 </Popover.Content>
45 </Popover.Root>
46 </div>
47 );
48}수동으로 닫기
1"use client";
2
3import { useState } from "react";
4import { Button, Popover } from "motile-ui";
5
6export default function NoAutoCloseExample() {
7 const [open, setOpen] = useState(false);
8
9 return (
10 <Popover.Root
11 open={open}
12 onOpenChange={setOpen}
13 position="bottom"
14 align="center"
15 variant="outlined"
16 autoClose={false}
17 >
18 <Popover.Trigger asChild>
19 <Button variant="primary">No Auto Close</Button>
20 </Popover.Trigger>
21 <Popover.Content>
22 <h3 style={{ margin: "0 0 8px 0", fontSize: "16px", fontWeight: 600, color: "#374151" }}>
23 수동으로 닫기
24 </h3>
25 <p style={{ margin: "0 0 12px 0", fontSize: "14px", color: "#374151", lineHeight: 1.6 }}>
26 ESC 키나 외부 클릭으로 닫히지 않습니다. 버튼을 클릭해주세요.
27 </p>
28 <Button
29 variant="secondary"
30 size="small"
31 onClick={() => setOpen(false)}
32 >
33 닫기
34 </Button>
35 </Popover.Content>
36 </Popover.Root>
37 );
38}바운스 애니메이션
1"use client";
2
3import { Button, Popover } from "motile-ui";
4
5export default function BounceAnimationExample() {
6 return (
7 <div style={{ display: "flex", gap: "16px", flexWrap: "wrap" }}>
8 <Popover.Root position="top" align="center" showArrow bounceCount={1}>
9 <Popover.Trigger asChild>
10 <Button variant="secondary">Bounce: 1</Button>
11 </Popover.Trigger>
12 <Popover.Content>
13 <p style={{ margin: 0, fontSize: "14px", color: "rgba(255, 255, 255, 0.9)" }}>
14 1번 통통 튑니다.
15 </p>
16 </Popover.Content>
17 </Popover.Root>
18
19 <Popover.Root position="top" align="center" showArrow bounceCount={3}>
20 <Popover.Trigger asChild>
21 <Button variant="secondary">Bounce: 3</Button>
22 </Popover.Trigger>
23 <Popover.Content>
24 <p style={{ margin: 0, fontSize: "14px", color: "rgba(255, 255, 255, 0.9)" }}>
25 3번 통통 튑니다.
26 </p>
27 </Popover.Content>
28 </Popover.Root>
29
30 <Popover.Root position="top" align="center" showArrow bounceCount="infinite">
31 <Popover.Trigger asChild>
32 <Button variant="secondary">Bounce: Infinite</Button>
33 </Popover.Trigger>
34 <Popover.Content>
35 <p style={{ margin: 0, fontSize: "14px", color: "rgba(255, 255, 255, 0.9)" }}>
36 무한 통통 튑니다.
37 </p>
38 </Popover.Content>
39 </Popover.Root>
40 </div>
41 );
42}