Skip to content

Commit 3a3990b

Browse files
authored
feat(Popover): add programmatic close functionality to popover root (#1956)
1 parent b6951ce commit 3a3990b

File tree

4 files changed

+117
-1
lines changed

4 files changed

+117
-1
lines changed

docs/content/docs/components/popover.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,31 @@ import { PopoverAnchor, PopoverArrow, PopoverClose, PopoverContent, PopoverPorta
318318
}
319319
```
320320

321+
### Close using slot props
322+
323+
Alternatively, you can use the `close` method provided by the `PopoverRoot` slot props to programmatically close the popover.
324+
325+
```vue line=4,8,16-20
326+
<script setup>
327+
import { PopoverAnchor, PopoverArrow, PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger } from 'reka-ui'
328+
</script>
329+
330+
<template>
331+
<PopoverRoot v-slot="{ close }">
332+
<PopoverTrigger>Open</PopoverTrigger>
333+
<PopoverAnchor />
334+
<PopoverPortal>
335+
<PopoverContent>
336+
<button type="submit" @click="close">
337+
Submit
338+
</button>
339+
<PopoverArrow />
340+
</PopoverContent>
341+
</PopoverPortal>
342+
</PopoverRoot>
343+
</template>
344+
```
345+
321346
## Accessibility
322347

323348
Adheres to the [Dialog WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/).

docs/content/meta/PopoverRoot.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,10 @@
3636
'name': 'open',
3737
'description': '<p>Current open state</p>\n',
3838
'type': 'boolean'
39+
},
40+
{
41+
'name': 'close',
42+
'description': '<p>Close the popover</p>\n',
43+
'type': '(): void'
3944
}
4045
]" />

packages/core/src/Popover/PopoverRoot.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ defineSlots<{
5656
default?: (props: {
5757
/** Current open state */
5858
open: typeof open.value
59+
/** Close the popover */
60+
close: () => void
5961
}) => any
6062
}>()
6163
@@ -87,6 +89,9 @@ providePopoverRootContext({
8789

8890
<template>
8991
<PopperRoot>
90-
<slot :open="open" />
92+
<slot
93+
:open="open"
94+
:close="() => open = false"
95+
/>
9196
</PopperRoot>
9297
</template>
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<script setup lang="ts">
2+
import { Icon } from '@iconify/vue'
3+
import {
4+
PopoverArrow,
5+
PopoverContent,
6+
PopoverPortal,
7+
PopoverRoot,
8+
PopoverTrigger,
9+
} from '..'
10+
</script>
11+
12+
<template>
13+
<Story
14+
title="Popover/ProgrammaticClose"
15+
:layout="{ type: 'single', iframe: true }"
16+
>
17+
<Variant title="default">
18+
<div class="relative flex items-center justify-center flex-col">
19+
<PopoverRoot v-slot="{ close: closeA }">
20+
<PopoverTrigger
21+
class="rounded-full w-[35px] h-[35px] inline-flex items-center justify-center text-violet11 bg-white shadow-[0_2px_10px] shadow-blackA7 hover:bg-violet3 focus:shadow-[0_0_0_2px] focus:shadow-black cursor-default outline-none"
22+
aria-label="Open popover 1"
23+
>
24+
<button>
25+
<Icon icon="radix-icons:mixer-horizontal" />
26+
</button>
27+
</PopoverTrigger>
28+
<PopoverPortal>
29+
<PopoverContent
30+
side="bottom"
31+
:side-offset="5"
32+
class="rounded p-5 w-[260px] bg-white shadow-[0_10px_38px_-10px_hsla(206,22%,7%,.35),0_10px_20px_-15px_hsla(206,22%,7%,.2)] focus:shadow-[0_10px_38px_-10px_hsla(206,22%,7%,.35),0_10px_20px_-15px_hsla(206,22%,7%,.2),0_0_0_2px_theme(colors.violet7)] will-change-[transform,opacity] data-[state=open]:data-[side=top]:animate-slideDownAndFade data-[state=open]:data-[side=right]:animate-slideLeftAndFade data-[state=open]:data-[side=bottom]:animate-slideUpAndFade data-[state=open]:data-[side=left]:animate-slideRightAndFade"
33+
>
34+
First Popover
35+
<button
36+
aria-label="Close"
37+
class="rounded-full h-[25px] w-[25px] inline-flex items-center justify-center text-violet11 absolute top-[5px] right-[5px] hover:bg-violet4 focus:shadow-[0_0_0_2px] focus:shadow-violet7 outline-none cursor-default"
38+
@click="closeA"
39+
>
40+
<Icon icon="radix-icons:cross-2" />
41+
</button>
42+
43+
<PopoverRoot v-slot="{ close: closeB }">
44+
<PopoverTrigger
45+
aria-label="Open popover 2"
46+
>
47+
Open nested popover
48+
</PopoverTrigger>
49+
<PopoverPortal>
50+
<PopoverContent
51+
side="top"
52+
align="center"
53+
:side-offset="5"
54+
class="rounded p-5 w-[260px] bg-white shadow-[0_10px_38px_-10px_hsla(206,22%,7%,.35),0_10px_20px_-15px_hsla(206,22%,7%,.2)] focus:shadow-[0_10px_38px_-10px_hsla(206,22%,7%,.35),0_10px_20px_-15px_hsla(206,22%,7%,.2),0_0_0_2px_theme(colors.violet7)] will-change-[transform,opacity] data-[state=open]:data-[side=top]:animate-slideDownAndFade data-[state=open]:data-[side=right]:animate-slideLeftAndFade data-[state=open]:data-[side=bottom]:animate-slideUpAndFade data-[state=open]:data-[side=left]:animate-slideRightAndFade"
55+
>
56+
Second popover
57+
<button
58+
aria-label="Close"
59+
class="rounded-full h-[25px] w-[25px] inline-flex items-center justify-center text-violet11 absolute top-[5px] right-[5px] hover:bg-violet4 focus:shadow-[0_0_0_2px] focus:shadow-violet7 outline-none cursor-default"
60+
@click="closeB"
61+
>
62+
<Icon icon="radix-icons:cross-2" />
63+
</button>
64+
<PopoverArrow
65+
:width="20"
66+
:height="10"
67+
:offset="20"
68+
:style="{ fill: 'green' }"
69+
/>
70+
</PopoverContent>
71+
</PopoverPortal>
72+
</PopoverRoot>
73+
74+
<PopoverArrow style="fill: crimson" />
75+
</PopoverContent>
76+
</PopoverPortal>
77+
</PopoverRoot>
78+
</div>
79+
</Variant>
80+
</Story>
81+
</template>

0 commit comments

Comments
 (0)